Go: Asynchronous Preemption
ℹ️ This article is based on Go 1.14.
The preemption is an important part of the scheduler that lets it distribute the running time among the goroutines. Indeed, without preemption, a long-running goroutine that hogs the CPU would block the other goroutines from being scheduled. The version 1.14 introduces a new technique of asynchronous preemption, giving more power and control to the scheduler.
For more details about the previous behavior and its drawback, I suggest you read my article “Go: Goroutine and Preemption.”
Workflow
Let’s start with an example where preemption is needed. Here is a code where many goroutines loop for a while without any function call, meaning no opportunity for the scheduler to preempt them:
However, when visualizing the traces from this program, we clearly see the goroutines are preempted and switch among them:
We can also see that all the blocks representing the goroutines have the same length. The goroutines get almost the same running time (around 10/20ms):
The asynchronous preemption is triggered based on a time condition. When a goroutine is running for more than 10ms, Go will try to preempt it.
The preemption is initiated by the thread sysmon
, dedicated to watching after the runtime, long-running goroutines included. Once a goroutine is detected running more than 10ms, a signal is emitted to the current thread for its preemption:
Then, once the message is received by the signal handler, the thread is interrupted to handle it, and therefore does not run the current…