Go: g0, Special Goroutine

ℹ️ This article is based on Go 1.13.
All the goroutines created in Go are under the management of an internal scheduler. The Go scheduler tries to give running time to all goroutines and keep all CPU busy with running goroutines when the current ones are blocked or terminated. It actually runs as a special goroutine.
Scheduling goroutine
Go limits the number of OS thread running thanks to GOMAXPROCS
variable simultaneously. That means Go has to schedule and manage goroutines on each of the running threads. This role is delegated to a special goroutine, called g0
, that is the first goroutine created for each OS thread:

Then, it will schedule ready goroutines to run on the threads.
For more information about the P
, M
, G
model, I suggest you read my article “Go: Goroutine, OS Thread and CPU Management.”
To better understand how scheduling works on g0
, let’s review the usage of the channels. Here is when a goroutine blocks on sending on channels:
ch := make(chan int)
[...]
ch <- v
When blocking on channels, the current goroutine will be parked, i.e., be in waiting mode and not been pushed in any goroutines queues:

Then, g0
replaces the goroutine and does on round one scheduling:

The local queue has the priority during the scheduling, and the goroutine #2 will now run:

For more information about scheduling priority, I suggest you read my article “Go: Work-Stealing in Go Scheduler.”
The goroutine #7 will get unblocked as soon as a receiver comes with reading the channel:
v := <-ch
The goroutine receiving the message will switch to g0
and unlock the parked goroutine by putting it on the local queue:

Although the special goroutine is managing the scheduling, it is not its only job, it does much more.
Responsibilities
Contrary to the regular goroutines, g0
has a fix and larger stack. This allows Go to perform operations where a bigger stack is needed, and when it is preferable for the stack not to grow. Among the responsibilities of g0
, we can list:
- Goroutine creation. When calling
go func(){ ... }()
orgo myFunction()
, Go will delegate the function creation tog0
before putting it on the local queue:

Newly created goroutines run in priority and are placed at the top of the local queue.
For more information about the prioritization of the goroutines, I suggest you read my article “Go: Concurrency & Scheduler Affinity.”
- Defer functions allocations.
- Garbage collector operations, such as stopping the world, scanning the stack of the goroutines, and some of the marking and sweeping operations.
- Stack growth. When needed, Go increases the size of the goroutines. This operation is done by
g0
in the prolog functions.
Involved in many other operations (large allocations, cgo, etc.), this special goroutine g0
makes our program more efficient managing operations with a need of larger stack to keep our program more efficient with low memory print.