Channels

A common challenge when using threads is to coordinate the communication between them. Go provides a mechanism to solve this problem: channels.










  • goroutines can communicate with each other using channels, which is a special type of variable.
  • A channel can contain a value of any kind.
  • A goroutine can send a value to a channel and another goroutine can receive it.
  • Channels can be buffered or unbuffered.









Using channels

Unbuffered

var ch chan string

ch := make(chan string)

ch <- "hello"

message := <-ch


Example

func main() {
    ch := make(chan int)
    go func() {
        ch <- 42
    }()
    fmt.Println(<-ch)
}

The func() here is an example of an anonymous function, or a lambda.










Buffered

We can also have buffered channels.

In this case we specify the number of values that can be stored in the channel.

ch := make(chan string, 2)
ch <- "hello"
ch <- "world"

fmt.Println(<-ch)
fmt.Println(<-ch)

If you pull a message from the buffer, the thread will wait until a message is sent to the channel.










Things to be aware of

  • Deadlocks can occur if a channel is not closed.
close(channel)

Good practice: Use the defer keyword to close the channel and to keep code in related blocks.










Waitgroups

A waitgroup is a way to wait for a collection of goroutines to finish.

var wg sync.WaitGroup

wg.Add(1)
go func() {
    defer wg.Done()
    fmt.Println("Hello")
}()
wg.Wait()