Go: Goroutine and Preemption
ℹ️ This article is based on Go 1.13.
ℹ️ Go implements an asynchronous preemption in Go 1.14, making some part of this article obsolete. However, those sections will be marked as it, making the article still useful to understand the need for the asynchronous preemption.
For more details about asynchronous preemption, I suggest you read “Go: Asynchronous Preemption.”
Go manages the goroutines thanks to an internal scheduler. This scheduler aims to switch goroutines between them and make sure they all can get runnable time. However, the scheduler could need to preempt the goroutines to establish a correct turnover.
Scheduler and preemption
Let’s use a simple example to show how the scheduler works:
For ease of reading, the examples will not use atomic operations.
func main() {
var total int
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
for j := 0; j < 1000; j++ {
total += readNumber()
}
wg.Done()
}()
}
wg.Wait()
}
//go:noinline
func readNumber() int {
return rand.Intn(10)
}
Here is the tracing: