Golang concurrency

From wikinotes
Revision as of 20:29, 6 June 2022 by Will (talk | contribs)

This page is about the methods of concurrency provided by go.
If you're looking for synchronization primitives (ex. mutexes, semaphores, ... see golang synchronization)

Not Present

Go does not:

  • expose OS-threads, you only have access to it's green-threads
  • abstract multiprocessing, but you could roll your own with a subprocess and IPC if you wanted to
  • provide a message-queue implementation, use channels instead

Goroutines

Usage

Goroutines use green-threads rather than os-threads.
An OS thread is relatively expensive in setup and memory. One thread is reserved for a particular stack.
Go abstracts threads/threadpools with goroutines to make threads relatively cheap.

func doThing() {
    fmt.Println("hi")
}

func main() {
    go sayHello()  // <-- run in thread
}

Go functions default to using value objects rather than references.
Depending on your datastructure, this makes goroutines fairly concurrency-safe, since it operates on a copy of the data, rather than the same data.

func printThing(a string) {
    fmt.Println(a)
}

go printThing("abc")

Testing

go run -race foo.go  # run, checking for race conditions

Limits

Threads are a finite resource. You only have so many CPU cores, and CPU cores can only evaluate one thread at a time. Go defaults to allowing one thread per core, but you can generally get additional performance by increasing this.

require "runtime"

runtime.GOMAXPROCS(-1)  // show configured max-number of threads
runtime.GOMAXPROCS(2)   // set max-number of threads

Channels

Channels serve as a message queue for it's goroutines.
Channels are typed, and you may optionally restrict it to direction (ex. read/write only).

Channels are FIFOs.

ch := make(chan int) // create a channel that passes ints

num := <- ch  // read next item in channel
ch <- 123     // append next item to channel

You can specify the direction of the information flow in a method signature

go func(ch <-chan int) { ... } // read-only channel
go func(ch chan<- int) { ... } // write-only channel