Fundamentals 7 min read

How Does Go’s Scheduler Perform Context Switching? A Deep Dive

This article explains the concept of context switching, compares process, thread, and coroutine switches, and details how Go’s M:N scheduler implements low‑cost coroutine switches with examples, costs, and optimization tips for writing efficient concurrent programs.

Ops Development & AI Practice
Ops Development & AI Practice
Ops Development & AI Practice
How Does Go’s Scheduler Perform Context Switching? A Deep Dive

Introduction

Multitasking is ubiquitous in modern computer systems, and operating systems must switch between tasks on a single processor. This operation, known as a context switch, is crucial for Go developers to understand in order to write efficient concurrent programs.

What Is a Context Switch?

A context switch is the process by which the OS saves the state of the currently running task (registers, program counter, etc.) and loads the state of the next task.

Save the current task’s context.

Load the next task’s context.

Transfer the processor to the next task.

Types of Context Switches

Process context switch : switches between different processes; highest cost because it requires changing the address space.

Thread context switch : switches between threads within the same process; lower cost as threads share the address space.

Coroutine (goroutine) context switch : switches between lightweight coroutines within a single thread; lowest cost and forms the basis of Go’s concurrency model.

Context Switching in Go

Go’s concurrency model relies on goroutines and a built‑in scheduler. Goroutines are lightweight threads managed by the Go runtime, and the scheduler performs context switches between them.

Go Scheduler Mechanism

The scheduler uses an M:N model, mapping M goroutines onto N OS threads. Its core components are:

G (Goroutine) : a runnable goroutine.

M (Machine) : an OS thread.

P (Processor) : a logical processor that executes goroutines.

Scheduler Work Process

Goroutine creation : a new goroutine is placed in the global queue or a local P queue.

Scheduling loop : each P runs a loop that continuously pulls goroutines from its local queue or the global queue for execution.

Context switch : when a goroutine blocks or yields the CPU, the scheduler saves its context and loads the next goroutine’s context.

Cost of Context Switching

Even though coroutine switches are cheap, they still incur overhead in three main areas:

CPU time : saving and restoring context consumes CPU cycles.

Cache invalidation : switches may flush CPU caches, reducing performance.

Memory overhead : additional memory is needed to store context information.

The Go scheduler mitigates these costs with optimizations such as reducing global lock usage and improving the goroutine scheduling algorithm.

Practical Example: Context Switching in Go

The following program creates two goroutines that print a counter and sleep for one second. The scheduler alternates execution between them, demonstrating a context switch.

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    runtime.GOMAXPROCS(2) // set maximum CPU cores
    go func() {
        for i := 0; i < 5; i++ {
            fmt.Println("Goroutine 1:", i)
            time.Sleep(1 * time.Second)
        }
    }()

    go func() {
        for i := 0; i < 5; i++ {
            fmt.Println("Goroutine 2:", i)
            time.Sleep(1 * time.Second)
        }
    }()

    time.Sleep(6 * time.Second) // wait for goroutines to finish
}

Running the program yields interleaved output such as:

Goroutine 1: 0
Goroutine 2: 0
Goroutine 2: 1
Goroutine 1: 1
Goroutine 1: 2
Goroutine 2: 2
Goroutine 2: 3
Goroutine 1: 3
Goroutine 1: 4
Goroutine 2: 4

Conclusion

Context switching is a key technology for multitasking. For Go developers, understanding its principles and the scheduler’s implementation is essential for building high‑performance concurrent applications. While Go’s lightweight goroutine switches are inexpensive, developers must still be aware of their potential overhead and apply appropriate optimizations.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

concurrencyGoSchedulerRuntimeGoroutinecontext switching
Ops Development & AI Practice
Written by

Ops Development & AI Practice

DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.