Golang Tutorial – Working with Go Channels

Golang Channels

This article’s author works with Golang daily as a developer on the OpenZiti project. In learning Go, I’ve hit various stumbling blocks, settled on some best practices, and hopefully improved at writing Go code. This series shares some of the ‘Aha!’ moments I’ve had overcoming obstacles and finding solutions that sparked joy.

This series targets new team members and anyone in the Golang community who might be interested. We’d be very happy to hear from others about their own ‘aha’ moments and how the presented solutions strike your sensibilities. Suggested improvements, corrections, and constructive criticism are welcome.

This first installment will cover various topics related to Golang channels.

Golang Channels

Channels are a core feature of Go. As is typical of Golang, the channel API is small and simple but provides a lot of power.

See here for a quick Go channels refresher. Also, if you haven’t read it yet, Dave Cheney’s Channel Axioms is worth a look.

Go Channels For Signals

Simple Broadcast

There are a few ways we can use channels to signal other goroutines. The first is if we want to broadcast a one-time notification. For example, suppose you have something with several associated goroutines and want to clean them together. In that case, you can use a single unbuffered channel which they can monitor for closes.

For example, you might have a UDP socket listener handling UDP connections. Since UDP doesn’t have timeouts, you must ensure idle connections are eventually cleaned up. So you create an idle connection scanner. You want the goroutine for this scanner to stop when the UDP socket listener is closed, so you pass it a channel that you’ll close when the socket is closed.COPYCOPYCOPYCOPY

import (

type IdleScanner struct {
    closeNotify <-chan struct{}

func (self *IdleScanner) run() {
    ticker := time.NewTicker(time.Minute)
    defer ticker.Stop()

    for {
        select {
        case <- ticker.C:
            // scan for idle connections
        case <- self.closeNotify:
            return // shutting down

Note that the IdleScanner has a <- chan, so it can only check if the channel is closed, it cannot close the channel itself.