8 Concurrency: Foundations

 

This chapter covers

  • Understanding concurrency and parallelism
  • Why concurrency isn’t always faster
  • The impacts of CPU-bound and I/O-bound workloads
  • Using channels vs. mutexes
  • Understanding the differences between data races and race conditions
  • Working with Go contexts

In recent decades, CPU vendors have stopped focusing only on clock speed. Instead, modern CPUs are designed with multiple cores and hyperthreading (multiple logical cores on the same physical core). Therefore, to leverage these architectures, concurrency has become critical for software developers. Even though Go provides simple primitives, this doesn’t necessarily mean that writing concurrent code has become easy. This chapter discusses fundamental concepts related to concurrency; chapter 9 will then focus on practice.

8.1 #55: Mixing up concurrency and parallelism

Even after years of concurrent programming, developers may not clearly understand the differences between concurrency and parallelism. Before delving into Go-specific topics, it’s first essential to understand these concepts so we share a common vocabulary. This section illustrates with a real-life example: a coffee shop.

In this coffee shop, one waiter is in charge of accepting orders and preparing them using a single coffee machine. Customers give their orders and then wait for their coffee (see figure 8.1).

Figure 8.1 A simple coffee shop

8.2 #56: Thinking concurrency is always faster

8.2.1 Go scheduling

8.2.2 Parallel merge sort

8.3 #57: Being puzzled about when to use channels or mutexes

8.4 #58: Not understanding race problems

8.4.1 Data races vs. race conditions

8.4.2 The Go memory model

8.5 #59: Not understanding the concurrency impacts of a workload type