Multiplexing fizzbuzz

By Chee Leong

I’m trying to show the common pattern of multiplexing via gochannel and goroutine.

Definition

Fizz buzz is a group word game for children to teach them about division.[1] Players take turns to count incrementally, replacing any number divisible by three with the word "fizz", and any number divisible by five with the word "buzz".

Attention! Go Playground operation is single threaded hence output is always in order of the input. Try the code out at your computer for multithread goodness.

Basic

Let’s start with the basic example,

Playground Link

As demonstrated above, each loop contains blocking operation of processing and output.

Goroutine

To start applying goroutine, the inner loop operations are moved to a separate function.

To invoke a goroutine, simply append a go keyword in front of the function call.

Playground Link

As you can see, we rely on a blocking Sleep operation to stall the main from exiting too early. However this is not good idea because we have no idea how long it takes for each processes to finish running.

Synchronization

Synchronization via WorkGroup

Although it is possible to do job waiting with channel, it is recommended to use WaitGroup

Playground Link

Now, we made sure all goroutine executed before exit.

Even though the current code looks good enough, fmt.Println is actually a io operation.

If the write buffer is big enough, you will notice the output is contaminated, ie part of line 1 will have fragment of line 3.

To avoid undesirable side effect, we’ll apply multiplexing.

Multiplex

Unfortunately, I won’t be covering channel here. For the uninitiated, it is a pipe.

Read more about channel here.

The diagram of multiplexing we’re going to apply here

     inputChan                | 0 | ouputChan
main ========> fizzbuzzWorker | 1 | ========> printWorker
                              | 2 |
                              | 3 |

The changes for this implement might be a bit drastic

Playground Link

As you can see, the last part is declared first, aka in our example the printWorker and outputChan.

This is to assure the worker is consuming the piped message as soon as possible.

Since printWorker is only a single process, we’ll be using a channel to signal the conclusion of the goroutine.

printWorker listen to incoming string message and print them out on the terminal.

Then, we starts n (system core) amount of fizzbuzzWorker goroutine.

fizzbuzzWorker ingests int input, and ouput string

Now, with all the worker set, we start to feed inputChan. Once it’s finished, we closed inputChan so our fizzbuzzWorker knows when there’s no more job and exit.

Warning, failed to close a channel will result in a deadlock, the best case is the compiler or runtime throws panic immediately, worst case is the program stucked but still run indefinitely.

Next, the program waits for all n of fizzbuzzWorker to finish their task, then we’ll close outputChan so printWorker knows when to stop.

Once, printWorker finished its job, the printDone is signalled and program is now exited happily.

References

  1. Fizz buzz
  2. Multiplexing
  3. Go by Example
comments powered by Disqus