Goroutines and Channels
Table of Contents
Goroutines tutorial
Syntactically, a
go
statement is an ordinary function or method call prefixed by the keywordgo
.There is no programmatic way for one goroutine to stop another.
Basics of chan
(Channels) tutorial
ch := make(chan int) // unbuffered
ch := make(chan int, 0) // unbuffered
ch := make(chan int, 3) // buffered with capacity 3
ch <- x // a send statement
<-ch // a receive statement; result is discarded
x = <-ch // a receive expression in an assignment statement
// `close' sets a flag indicating that no more values will ever be sent on this channel;
// subsequent attempts to send will panic.
// Receive operations on a closed channel yield the values that have been sent until no more values are left;
close(ch)
- A send operation on an unbuffered channel blocks the sending goroutine until another goroutine executes a corresponding receive on the same channel.
- Conversely, if the receive operation was attempted first, the receiving goroutine is blocked until another goroutine performs a send on the same channel.
ch := make(chan int)
for {
x, ok := <-ch
if !ok {
break // channel was closed and drained
}
// Do something with x
}
// Instead of doing it clumsy, just use range
for x := range ch {
// Do something with x
}
- You need not close every channel when you've finished with it.
- It's only necessary to close a channel when it is important to tell the receiving goroutines that all data have been sent.
Attempting to close an already-closed channel also causes a panic.
- Go type system provides unidirectional channel types that expose only one or the other of the send and receive operations.
- When a channel is buffered, the send operation add the element at the back of the queue, and blocked if it's full.
len(ch)
returns the number of elements currently buffered,cap(ch)
returns the buffer size.- There might be a goroutine leak if you send elements more than the buffer size and the number of receive called.
Two of these goroutines won't finish.
As like other functions, the iterator variable changes over iteration. So in case running gorotine within a loop, pass it as a same-named argument
Go supports multiplexing with
select
If multiple cases are ready,
select
picks one uniformly at random.
Avoid a data race howto
- Init a variable before running concurrently, and make it not to write
- Confine a variable in a single goroutine.
- Allow many goroutines to access the variable, but only one at a time. There are things like
sync.Mutex
,sync.RWMutex
, andsync.Once
. - Use
-race
flag to yourgo build
,go run
, orgo test
command to exploit race detector.
Goroutines and Threads discussion
- A goroutine starts life with a small stack, typically 2KB. It grows and shrinks as needed.
- The Go runtime contains its own scheduler that uses a technique known as m:n scehduling, because it multiplexes m goroutines on n OS threads.
- Go scheduler is invoked implicitly by certain Go language constructs.
- By design, Goroutines have no notion of identity that is accessible to the programmer.