What is a Goroutine?

July 18, 2019

Check this post if you want refresh your memory about multitasking and multithreading core concepts.

Let’s define a Coroutine

A coroutine is a function that can suspend execution to be resumed later.

In others words we could say: coroutines are functions where the control is transferred from one function to the other function in a way that the exit point from the first function and the entry point to the second function are remembered – without changing the context.

Thus, each function remembers where it left the execution and where it should resume from.

Since threads are managed by the OS while coroutines by the users, coroutines are light-weight threads. A light weight thread means it doesn’t map on native thread, so it doesn’t require context switching on processor, so they are faster.

So why Goroutines?

Called goroutines because the existing terms: threads, coroutines, processes, and so on, convey inaccurate connotations.

A goroutine has a simple model:

  • a function executing concurrently with other goroutines in the same address space
  • lightweight, costing little more than the allocation of stack space
    • the stacks start small, so they are cheap, and grow by allocating (and freeing) heap storage as required

Goroutines are multiplexed onto multiple OS threads so if one should block, such as while waiting for I/O, others continue to run.

Their design hides many of the complexities of thread creation and management.

  • goroutines imply parallelism; coroutines in general do not
  • goroutines communicate via channels; coroutines communicate via yield and resume operations

Goroutines vs Threads

Goroutine Threads
Managed by go runtime Managed by Kernel
Stack size is managed in run-time and (starting from 2KB) can grow allocating and freeing heap storage Fixed stack size of 1-2MB determined during compile time
Use channels to communicate with other goroutines - low latency Threads communication it’s not easy to implement - huge latency
Created and destoryed by the go’s runtime. Cheap operations compared to threads since go runtime already maintain a pool of threads for goroutines. Os is not aware of goroutines Significant setup and teardown cost as a thread has to request lots of resources from Os and return once it’s done
Coopertively scheduled. When a goroutine switch occurs, only 3 registers need to be saved or restored. Preemptively scheduled. Switching cost between threads is high as scheduler needs to save/restore all registers and states. This can be quite significant when there is rapid switching between threads

How to start a Goroutine?

Call a function with the go keyword and you will have a new Goroutine running concurrently.

package main

import (  
   "fmt"
)

func hello() {  
   fmt.Println("Hello world goroutine")
}
func main() {  
   go hello()
   fmt.Println("main function")
}

Run program in playground

Surprise! What happened to our Goroutine? This program print only “main function”.

  • when a new goroutine is started, the goroutine call returns immediately to the next line of code (any return values are ignored)

In our example, the main goroutine terminates and no other goroutine will run.

If we put to sleep for one second the main goroutine…

package main

import (  
    "fmt"
    "time"
)

func hello() {  
    fmt.Println("Hello world goroutine")
}
func main() {  
    go hello()
    time.Sleep(1 * time.Second)
    fmt.Println("main function")
}

Run program in playground

…we will see the output of our ‘hello’ goroutine.

How goroutines are executed?

The Go runtime manages the goroutines throughout from creation to scheduling to teardown.

  • allocate few threads on which all the goroutines are multiplexed
  • at any point of time, each thread will be executing one goroutine
  • if that goroutine is blocked, then it will be swapped out for another goroutine that will execute on that thread instead

Next time I’ll post a very detailed article about the Go scheduler…stay tuned!

References

How Goroutines works

Concurrency is not parallelism by Rob Pike

Effective Go: Goroutines

Dmitry Vyukov explains scheduling of goroutines on golang-nuts

5 things that make Go fast by Dave Cheney

Achieving concurrency in Go