A Tour of Go - Concurrency Flashcards
What is a goroutine?
A goroutine is a lightweight thread managed by the Go runtime.
go f(x, y, z)
starts a new goroutine running
f(x, y, z)
The evaluation of f
, x
, y
, and z
happens in the current goroutine and the execution of f
happens in the new goroutine.
Do goroutines share an address space?
Yes, so access to shared memory must be synchronised. The sync
package provides useful primitives.
What is a channel?
Channels are typed conduits through which you can send and receive values with the channel operator <-
.
ch <- v // Send v to channel sh v := <-ch // Receive from ch, and // assign value to v
How you do create a channel?
Like maps and slices, channels must be created before use:
ch := make(chan int)
By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.
What is a buffered channel?
Channels can be buffered. Provide the buffer length as a second argument to make
to initialise a buffered channel:
ch := make(chan int, 100)
Sends to a buffered channel block only when the buffer is full.
Receives block when the buffer is empty.
How does a sender close a channel?
Using the close built-in:
close(c)
How can you check if a channel has been closed?
Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression:
v, ok := <-ch
ok
is false
if there are no more values to receive and the channel is closed.
Can the range form of the for loop be used on a channel?
Yes,
for i := range c
The loop receives values from the channel repeatedly until it is closed.
Can you send to a closed channel?
Only the sender should close a channel, never a receiver. Sending on a closed channel will cause a panic.
Channels aren’t like files; you don’t usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range
loop.
What is a select statement?
The select
statement lets a goroutine wait on multiple communication operations.
select { case c <- x: x, y = y, x+y case <-quit: fmt.Println("quit") return }
A select
blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.
Give an example of fibonacci using goroutines, channels and select.
package main import "fmt" func fibonacci(c, quit chan int) { x, y := 0, 1 for { select { case c <- x: x, y = y, x+y case <-quit: fmt.Println("quit") return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() fibonacci(c, quit) }
How does the default
case in a select
statement work?
The default
case in a select is run if no other case is ready.
Use a default
case to try a send or receive without blocking:
select { case i := <-c: // use i default: // receiving from c would block }
What is mutual exclusion?
Making sure only one goroutine can access a variable at one time to avoid conflicts.
How does Go support mutual exclusion?
The data structure that provides mutual exclusion is called a mutex.
Go’s standard library provides mutual exclusion with sync.Mutex
and its two methods:
Lock
Unlock
We can define a block of code to be executed in mutual exclusion by surrounding it with a call to Lock
and Unlock
.
defer
can be used to ensure the mutex will be unlocked.