> For the complete documentation index, see [llms.txt](https://dianadarie.gitbook.io/go-guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dianadarie.gitbook.io/go-guide/concurrency/scheduling.md).

# Scheduling

Go's mechanism for hosting goroutines is an implementation of what's called an <mark style="color:yellow;">**M:N scheduler**</mark>: which states that <mark style="color:yellow;">**M**</mark> number of goroutines can be distributed over <mark style="color:yellow;">**N**</mark> number of OS threads.

<figure><img src="https://3823520723-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ftue2QgzdNn8ByIbGUSa9%2Fuploads%2FZVO1NhBKctnIJGRWYbNp%2Fimage.png?alt=media&amp;token=8d6c11b6-b5c8-4fdb-95d0-868bbb28a1f3" alt=""><figcaption></figcaption></figure>

When a Go program starts => it is given a logical processor **P** for every virtual core => Every P is assigned an OS thread **M** => Every Go program is also given an initial G which is the path of execution for a Go program. OS threads are context-switched on and off a core, goroutines are context-switched on and off a M.

There are two run queues in the Go scheduler.

* **Global Run Queue (GRQ)**
* **Local Run Queue (LRQ)**

Each P is given given a LRQ that manages the goroutines assigned to be executed within the context of P. These goroutines take turn being context-switched on and off the M assigned to that P. GRQ is for goroutines that have not been assigned to a P yet.

<figure><img src="https://3823520723-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ftue2QgzdNn8ByIbGUSa9%2Fuploads%2FpjIVhlH6MBDjKbrTj3cI%2Fimage.png?alt=media&amp;token=c72f1c87-c949-44df-9d9e-78726266f22a" alt=""><figcaption></figcaption></figure>

When a goroutine is performing an asynchronous system call, P can swap the G off M and put in a different G for execution. However, when a goroutine is performing a synchronous system call, the OS thread is effectively blocked. Go scheduler will create a new thread to continue servicing the existing goroutines in the LRQ.

<figure><img src="https://3823520723-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ftue2QgzdNn8ByIbGUSa9%2Fuploads%2F98h3wY52NS9JsOI7w0Cc%2Fimage.png?alt=media&amp;token=04b8de1e-f115-4b97-a1f2-809d2d83c464" alt=""><figcaption></figcaption></figure>

Go follows a model of concurrency called the <mark style="color:yellow;">**fork-join model**</mark>:

* fork - at any point in the program, a ***child*** branch of execution can be split off and run concurrently with its ***parent***
* join - at some point in the future, the concurrent branches of execution will join back together

<img src="https://3823520723-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ftue2QgzdNn8ByIbGUSa9%2Fuploads%2FAULQT7MYdDlg9arDQcXs%2Fimage.png?alt=media&amp;token=5eefa396-96ae-4f25-a9ae-d281684700e9" alt="" data-size="original">
