Are goroutines appropriate for large, parallel, compute-bound problems?
The Go runtime has a model where multiple Go routines are mapped onto multiple threads in an automatic fashion. No Go routine is bound to a certain thread, the scheduler may (and will) schedule Go routines to the next available thread. The number of threads a Go program uses is taken from the GOMAXPROCS
environment variable and can be overriden with runtime.GOMAXPROCS(). This is a simplified description which is sufficient for understanding.
Go routines may yield in the following cases:
- On any operation that might block, i.e. any operation that cannot return a result on the spot because it is either a (possible) blocking system-call like
io.Read()
or an operation that might require waiting for other Go routines, like acquiring a mutex or sending to or receiving from a channel - On various runtime operations
- On function call if the scheduler detects that the preempted Go routine took a lot of CPU time (this is new in Go 1.2)
- On call to runtime.Gosched()
- On panic()
- As of Go 1.14, tight loops can be preempted by the runtime. As a result, loops without function calls no longer potentially deadlock the scheduler or significantly delay garbage collection. This is not supported on all platforms - be sure to review the release notes. Also see issue #36365 for future plans in this area.
- On various other occasions
The following things prevent a Go routine from yielding:
- Executing C code. A Go routine can't yield while it's executing C code via cgo.
- Calling runtime.LockOSThread(), until runtime.UnlockOSThread() has been called.