Appendix E. Concurrent programming

 
Concurrency is dealing with a lot of things at once. Parallelism is doing a lot of things at once.

— Rob Pike, from his Waza talk (https://go.dev/blog/waza-talk).

Concurrency may involve parallelism, but they are not the same. Concurrency is about structuring the code, while parallelism is about executing the code simultaneously.

Many goroutines can run concurrently on a single CPU through context switching, while parallelism may occur when multiple CPUs execute goroutines simultaneously. Grasping this distinction helps structure concurrent code regardless of the number of available CPUs.

We'll begin by exploring goroutines and channels. This appendix builds on concepts introduced earlier in Section 1.4; it's a good idea to review Chapter 1 to understand it fully.

WARNING

We'll often omit package and import declarations to save space and trees. If none is specified, assume the package is main. Listings can also omit the work function that we'll soon add. For full code, visit the book's GitHub repository.

E.1 Goroutines

Goroutines are lightweight and independently running concurrent functions. They can handle multiple tasks concurrently without the overhead of traditional threads. We'll examine how to start a goroutine and the differences between running sequential and concurrent code.

E.1.1 Sequential

E.1.2 Concurrent

E.2 WaitGroup

E.2.1 syncx.SafeGroup

E.2.2 Exercises

E.3 Unbuffered channels

E.3.1 Usage

E.3.2 Synchronization

E.3.3 Pattern: Sending and receiving

E.4 Closing channels

E.4.1 Pattern: For-range

E.4.2 Pattern: Coordinating with a closing signal

E.5 Select

E.5.1 Waiting for multiple channels

E.5.2 Pattern: Non-blocking operations

E.6 Buffered channels

E.6.1 Pattern: timing out

E.6.2 Directional channels

E.6.3 Pattern: Limiting concurrency

E.7 Exercises