Master Go Concurrency Patterns
Processes running concurrently on a separate thread from main.
A goroutine is a lightweight thread managed by the Go runtime.
go f(x, y, z)
starts a new goroutine running
f(x, y, z)
The evaluation of f, x, y, and z happens in the current goroutine and the execution of f happens in the new goroutine.
Goroutines run in the same address space, so access to shared memory must be synchronized. The sync package provides useful primitives, although you won't need them much in Go as there are other primitives.
Channels are FIFO queues typically used to communicate typed information between go routines.
Channels are a typed conduit through which you can send and receive values with the channel operator, <-.
ch <- v // Send v to channel ch
v := <- ch // Receive from ch, and assign value to v
(The data flows in the direction of the arrow.)
Like maps and slices, channels must be created before use:
ch := make(chan int)
By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.
The example code sums the numbers in a slice, distributing the work between two goroutines. Once both goroutines have completed their computation, it calculates the final result.
The select statement allows selecting the first operation ready to be executed from multiple channels. It can be a signal to perform some useful task or to exit the infinite loop.
select {
case msgFromChannelOne := <-channelOne:
fmt.Println(msgFromChannelOne)
case msgFromChannelTwo := <-channelTwo:
fmt.Println(msgFromChannelTwo)
}
Select statement will block the execution until it receive data from a channel.
To wait for goroutines to finish, we can use wait groups.
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
doSomethingConcurrently()
}()
}
wg.Wait()
A generator in computer science is a function, sometimes called a subroutine that produces values to iterate over. Those values can be the result of a computation. The iteration ends either when the generator stops producing values or when the caller terminates it explicitly (with the break keyword for instance).
The main idea of the for-select-done pattern is to use an infinite for loop to handle events from various channels using the select statement.
The select statement allows selecting the first operation ready to be executed from multiple channels. It can be a signal to perform some useful task or to exit the infinite loop.
In this pattern, the infinite for loop is usually called in a separate goroutine to avoid blocking the main thread.
The pipeline pattern allows you to easily compose sequential stages by chaining stages.
The Fan-In Fan-Out pattern allows you to execute several instances of a stage in a pipeline.
- Master Go Programming With These Concurrency Patterns (Video - part 1)
- Master Go Programming With These Concurrency Patterns (Video - part 2)
- Golang Concurrency Patterns
- Tour of Go - Concurrency
- Intro to Concurrency in Golang
- Golang closures and goroutines
- Concurrent data pipelines in Golang
- Generators With Go Channels
- Go Fan-In / Fan-Out pattern example