As we know that There is a runtime when Golang running. The runtime perform the scheduled tasks(goroutine) in user space rather than kernel, so it's more lightweight. It do a better tradeoff between system resource usage and performance, especially in IO tasks. In this article, I'll show you Golang scheduler's history, Goroutine scheduler GMP's design pattern, and some cases how does GMP handle.

We know why we need a scheduler in previous article. And GM pattern also have a bad performance, to fix this problem, a GMP pattern introduced into golang.

GMP Pattern

In this pattern, threads are the physical workers, scheduler should dispatch goroutines to one thread.

GMP Pattern

GMP Pattern

  1. global queue: goroutines to be executed.
  2. P, the local queue: like the global queue, it contains goroutines to be executed; But this queue have a max capacity 256. It will post half of total goroutines to global queue when the local is full; And finally, Goroutine G' created by G will be queued in the same one to ensure local relation
  3. P's list: all P's list will be created once GOMAXPROCS value is determined
  4. M: running thread should acquire tasks from P's local queue, if it's empty, M will fetch goroutines from global queue to P's local or fetch from other P's queue. G is running in M, it will keep pull a new G when task will finish

Goroutine scheduler and OS scheduler are connected using M, every M is a physical OS thread, OS scheduler dispatch M running in a real CPU core.

Numbers of M & P

Numbers of P:

Determined by GOMAXPROCS environment variable or GOMAXPROCS() function in runtime package. That means there are GOMAXPROCS goroutines run concurrent at any time.

Numbers of M: