Go Concurrency Part 1

Now we know what is a goroutine. Here are some fairly advanced use cases. Majority of the examples come from Rob Pike's talk. I made couple enhancements here and there. Try your best to understand them, but know that concurrency is difficult and it takes time to have a firm grasp.

Channels

Two goroutines can communicate and synchronize through channel.

func ping(msg string, c chan string) {
  for i := 0; ; i++ {
    c <- fmt.Sprintf("%s %d", msg, i)
    time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
  }
}

func main() {
  ch := make(chan string)
  go ping("ping", ch)

  for i := 0; i < 5; i++ {
    fmt.Println(<-ch)
    // The receiver end is blocking because it's waiting for a message to come through the channel.
  }

  fmt.Println("Enough pings, done!")
}

Generator

What if we want to listen to multiple pings? We can use a ping generator.

Here's a problem though, ch1 and ch2 are blocking each other. We are not really getting the live updates of ping.

Multiplexing

We can address the problem by multiplexing multiple channels into one.

However, we can easily spot that the messages are coming in out of order. What if I want the batch of messages to come in order, e.g.

Fan-in Sequencing

We will use a signal channel to achieve the wait. We wait for three pings and then tell them ready for the next batch of 3 pings. First, let's define a message struct.

Each message will carry a reference to a signal channel, called ready. When the channel receives a signal, it indicates that it's ready to process next message.

Select

If you already know how many channels you want to listen to, it's better to use select instead of fan-in. However, it's also reasonable to combine two techniques together. Let's say I want a timeout on my fan-in.

Quit Channel

We know how to terminate the reader, but how about the writer? Notice that despite the for-loop has terminated, the goroutine in each generator is not terminated. Let's do something clever, i.e. use a channel to signal quit. We need to stop using fanIn for a moment because that will cause a deadlock if we terminate the writer without terminating the goroutines from fanIn.

Now we can tell it to stop.

Receive on Quit

The problem is that how do we know the quit signal has been received and processed? We can wait for the quit channel to tell us that it is done! We make a channel that passes channel which passes string.

We would create a quit channel that passes a reply channel.

Daisy Chain

Let's try to pass data from one channel to another, and repeat this process many times. We are daisy chaining go routines.

For each pass, we increment the value of an integer by one.

Now create the goroutines and chain them up.

Last updated