Detect Data Race

“Data race” is a common but notorious issue in concurrency programs. sometimes it is difficult to debug and reproduce, especially in some big system, so this will make people very frustrated. Thankfully, the Go toolchain provides a race detector (now only works on amd64 platform.) which can help us quickly spot and fix this kind of issue, and this can save our time even lives! Take the following classic “data race” program as an example: [Read More]

Need not close every channel

You don’t need to close channel after using it, and it can be recycled automatically by the garbage collector. The following quote is from The Go Programming Language: You needn’t 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. A channel that the garbage collector determines to be unreachable will have its resources reclaimed whether or not it is closed. [Read More]

nil channel VS closed channel

The zero value of channel type is nil, and the send and receive operations on a nil channel will always block. Check the following example: package main import "fmt" func main() { var ch chan int go func(c chan int) { for v := range c { fmt.Println(v) } }(ch) ch <- 1 } The running result is like this: fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send (nil chan)]: main. [Read More]

Mutex - Mutual Exclusion Lock

Intro Mutexes let you synchronize data access by explicit locking, without channels. Sometimes it’s more convenient to synchronize data access by explicit locking instead of using channels. The Go standard library offers a mutual exclusion lock, sync.Mutex, for this purpose. Example - Basic usage Here’s a basic example illustrating Lock and Unlock: func main() { mutex := sync.Mutex{} mutex.Lock() go func() { mutex.Lock() // Wait for main to call Unlock fmt. [Read More]

Wait for goroutines Using WaitGroups

Syntax A sync.WaitGroup waits for a group of goroutines to finish. var wg sync.WaitGroup wg.Add(2) go func() { // Do work wg.Done() }() go func() { // Do work wg.Done() }() wg.Wait() First the main goroutine calls Add to set the number of goroutines to wait for. Then two new goroutines run and call Done when finished. At the same time, Wait is used to block until these two goroutines have finished. [Read More]

Go - select

Syntax The select statement waits for multiple send or receive operations simultaneously. // Blocks until there's data available on ch1 or ch2 select { case <-ch1: fmt.Println("Received from ch1") case <-ch2: fmt.Println("Received from ch2") } The statement blocks as a whole until one of the operations becomes unblocked. If several cases can proceed, a single one of them will be chosen at random. Send and receive operations on a nil channel block forever. [Read More]

Channels in Go

Intro A go maxim or proverb is: Do not communicate by sharing memory; instead, share memory by communicating. So what is a channel? A channel is a “typed” conduit (pipes) mechanism for goroutines to synchronize execution and communicate by passing values, using channel operator, <-. They are mechanism for communication between goroutines. Syntax // can only be used to send float64s chan<- float64 // can only be used to receive ints <-chan int // can be used to send and receive values of type Dosa chan Dosa (The data flows in the direction of the arrow. [Read More]

Goroutines - Go Coroutines

Syntax A goroutine is a lightweight thread managed by the Go runtime. go f(x, y, z) // notice go keyword 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. All goroutines in a single program share the same address space. So access to shared memory must be synchronized. The sync package provides useful primitives, although you won’t need them much in Go as there are other primitives. [Read More]