Understanding blocking nature of Golang Channel

Mipsmonsta
2 min readJan 6, 2022

--

Channel and go routines (for support of concurrency) go hand-in-hand. In the tour of Go, the official playground walkthrough, it’s stated:

Channels are a typed conduit through which you can send and receive values with the channel operator

And more importantly what’s said about the blocking nature of channel:

By default, sends and receives (channel) block until the other side is ready.

As a new learner of Golang, this do trips me up, and I am sure other are confounded. Today, I attempt to record and illustrate this blocking behavior with some code that hopefully will demystify the cryptic statement above.

Code Setup

In the code below, there are two go routines with the main program. The first go routine execute the senderRepeat function which takes in an unbuffered channel c. What it does is just using the ticker to tick forever after every seconds.

The second anonymous go routine function send an integer to a stop channel after 5 seconds. The main program do the following in sequence: (1) Create the two unbuffered channels — c and stopChannel; (2) run senderRepeat Go routine; (3) run anonymous function that send to stopChannel channel after 5 secs and (4) receive the c channel and print what is conveyed.

package mainimport (
"fmt"
"time"
)
func senderRepeat(c chan string) {
t := time.NewTicker(time.Second * 1)
for {
<-t.C
}
}
func main() {
stopChannel := make(chan string)
c := make(chan string)
go senderRepeat(c)
go func() {
time.Sleep(time.Second * 5)
fmt.Println("Running...")
stopChannel <- "stop"
fmt.Println("stop channel writes are non blocking")
}()
fmt.Println(<-c) }

Before reading on, can you guess the behavior of the program, or more specifically, will any of the go routines and main program blocks?

Execution of program

At first:

$ go run example12_7.go

After 5 seconds:

$ go run example12_7.go
Running...

And the program never stops…which mean that the main execution loop is not ending. But if you look at the last line of code in the main program:

fmt.Println(<-c)

it’s not a forever for loop. So the main program must have blocked at this line. From the “Running…” output after 5 seconds, we know the anonymous go routine is executing, but it’s blocked too at the stopChannel <- “stop” line.

Why blocking?

In a gist, there is no receiver for stopChannel<- sender and there is no sender for <-c receiver. In other words: the other side is not ready for each of these channels!

This pairing up of sender and receiver ensure that go routines or main programs are linked up and channel information are shared, without the program or routine ending prematurely.

Have a go to see try to see how you can unblock the stopChannel<- “stop” line and even the fmt.Println(<-c).

--

--

Mipsmonsta

Writing to soothe the soul, programming to achieve flow