In an earlier version of Go, the code below exhibited unexpected behavior when runtime.Gosched() was removed:
package main import ( "fmt" "runtime" ) func say(s string) { for i := 0; i < 5; i++ { runtime.Gosched() fmt.Println(s) } } func main() { go say("world") say("hello") }
Output with runtime.Gosched():
hello world hello world hello world hello world hello
Output without runtime.Gosched():
hello hello hello hello hello
When Go is run without specifying the GOMAXPROCS environment variable, all goroutines are scheduled for execution in a single OS thread. To make the program appear multithreaded, the Go scheduler must occasionally switch execution contexts.
Cooperative Multitasking:
Go uses a cooperative multitasking model, meaning goroutines must explicitly yield control to other goroutines. This contrasts with preemptive multitasking in OS threads, where the scheduler switches execution contexts transparently.
The Function of runtime.Gosched():
In the absence of preemptive multitasking, runtime.Gosched() allows goroutines to yield control to the scheduler. When a goroutine reaches a Gosched call, the scheduler instructs it to switch execution to another goroutine.
In the provided example, removing Gosched means the execution context never leaves the main routine. As a result, the "world" goroutine is never allowed to run, and no "world" messages are printed.
Setting GOMAXPROCS to a positive number (e.g., runtime.GOMAXPROCS(2)) allows Go to create up to that number of native threads. If GOMAXPROCS is greater than 1, goroutines can be scheduled to run in different threads, leading to true parallelism.
With GOMAXPROCS set to 2 or above, the goroutines in the example will be interleaved, even without runtime.Gosched(), demonstrating preemptive multitasking.
The above is the detailed content of Why is `runtime.Gosched()` Crucial for Interleaving Goroutine Output in Single-Threaded Go Programs?. For more information, please follow other related articles on the PHP Chinese website!