Go: Work-Stealing in Go Scheduler

Vincent
A Journey With Go
Published in
4 min readDec 4, 2019

--

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

ℹ️ This article is based on Go 1.13.

Creating goroutines in Go is easy and fast. However, Go can run them, at most, one per core at the same time and need a way to park the other goroutines and make sure the load is well balanced across the processors.

Goroutines queues

Go manages the awaiting goroutines at two levels thanks to the local queues and the global one. The local queues are attached to each processor, while the global queue is unique and available through all processors:

Global and local queues

Each local queue has a maximum capacity of 256, and any new incoming goroutine is pushed to the global queue after that. Here is an example with a program that spawns thousands of goroutines:

func main() {
var wg sync.WaitGroup

for i := 0;i < 2000 ;i++ {
wg.Add(1)
go func() {
a := 0

for i := 0; i < 1e6; i++ {
a += 1
}

wg.Done()
}()
}

wg.Wait()
}

Here are the traces of the scheduler done with two processors:

--

--