2020-07-05
Digging into Goroutines I
Go enables writing programs with concurrent threads of execution. And it does so by introducing the concept of goroutine.
A goroutine has a simple model: it is a function executing concurrently with other goroutines in the same address space.
in Effective Go
Before digging into goroutines, having an understanding on “how” the Go compiler and runtime work together in order to launch a goroutine will pave the path to its internals.
Note: the examples and tools used on this document are based on Go 1.12.9 (darwin/amd64 build).
Launching a goroutine
Launching a goroutine is just as simple as calling a function and can be achieved by writing a “go” statement.
A “go” statement starts the execution of a function call as an independent concurrent thread of control, or goroutine, within the same address space.
The source code below - main.go - has a “go” statement declared (at line 9), that launches a goroutine, executing the heavyWeightChamp
function in a different thread of execution.
|
|
The Go compiler turns the “go” statement into a call to the runtime.newproc
1 function. This can be verified by inspecting the application binary using objdump
2 tool as depicted in the script below.
|
|
The runtime.newproc
receives as function arguments:
- the size (in bytes) of the arguments of the function launched as a goroutine;
- a reference to the function launched as a goroutine, in this case, a reference to
heavyWeightChamp
function; - and all the arguments of the function launched as a goroutine.
At this point, we already know “how” the Go compiler and runtime work together to launch a goroutine: through the runtime.newproc
function.
runtime.newproc
The runtime.newproc
function is part of the runtime
package. Also the function name is “unexported”,
which means that it can only be referenced or used inside the runtime
package and it only can be called indirectly through a “go” statement.
runtime.newproc
is responsible for creating a goroutine, which runs the provided function, and placing it in a “waiting to run goroutines” queue.
Conclusion
- goroutines are created by calling the
runtime.newproc
function; - The
runtime.newproc
function can only be called indirectly through a “go” statement, the compiler replaces the statement by aruntime.newproc
call; - The
runtime.newproc
creates a goroutine and places in a “waiting to run” queue.