By Chee Leong
I’m trying to show the common pattern of multiplexing via gochannel and goroutine.
Fizz buzz is a group word game for children to teach them about division. 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.
Let’s start with the basic example,
As demonstrated above, each loop contains blocking operation of processing and output.
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.
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 via WorkGroup
Although it is possible to do job waiting with channel, it is recommended to use WaitGroup
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.
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
As you can see, the last part is declared first, aka in our example the
This is to assure the worker is consuming the piped message as soon as possible.
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
int input, and ouput
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
fizzbuzzWorker to finish their task, then we’ll close
printWorker knows when to stop.
printWorker finished its job, the
printDone is signalled and program is now exited happily.