Go scheduler
runtime.Gosched ¶
runtime.Gosched causes the current goroutine to yield, i.e. to get descheduled. This is rarely (never?) needed for correctness these days, as Go’s scheduler has been preemptive for a long time. However, this can be used to implement low-priority goroutines that shouldn’t compete with other goroutines for CPU resources. That is, a goroutine can run for 10 ms before it gets preempted. By calling runtime.Gosched, one can give up the remainder of their time slice, thus using a lower than fair share of the CPU.
If the system is mostly idle, a goroutine that called runtime.Gosched may get scheduled again almost immediately. In that case, runtime.Gosched merely wastes hundreds of nanoseconds on descheduling and rescheduling the goroutine. In itself, this is just a minor cost. However, when enabling Go runtime tracing, each deschedule and each schedule will emit events. This can lead to millions of events in the span of a second.
In fact, runtime.bgsweep used to be implemented as a trivial loop of
for {
sweep one span
runtime.Gosched()
}
causing precisely the issue mentioned earlier. This was improved upon in 8451529e9ab26901f952976f9dcadd498d808c32 in response to issue 54767 by not yielding if there are idle Ps, which would indicate that the system isn’t fully utilized and would be prone to rescheduling the yielding goroutine right away.