Skip to content

Instantly share code, notes, and snippets.

@NoraCodes
Created April 26, 2017 15:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NoraCodes/433654da49c93c2da347bb7b5f7adc79 to your computer and use it in GitHub Desktop.
Save NoraCodes/433654da49c93c2da347bb7b5f7adc79 to your computer and use it in GitHub Desktop.
A parallel FizzBuzz using Goroutines.
package main
import (
"fmt"
"strconv"
)
// Return a channel which will produce a stream of numbers
// from minimum to maximum minus one.
func intRange(minimum int, maximum int) <-chan int {
// ch is a two-way unbuffered channel. When a write is performed,
// the writing Goroutine blocks until some other routine performs
// a read on the other end of the channel, and vice versa.
ch := make(chan int)
// Here, an anonymous function is spun off to perform the required work
go func() {
for i := minimum; i < maximum; i++ {
// Write the value to the channel and block until it is read
ch <- i
}
// The channel is no longer needed. Closing the channel will unblock any
// Goroutine trying to read from it.
close(ch)
}() // These parentheses call this anonymous function
return ch // Because of the type signature of the function, only
// the recieving end of the channel is actually returned.
}
// Perform the actual FizzBuzz calculation
func checkFizzBuzz(value int) string {
var s string
if value % 3 == 0 {
s += "Fizz"
}
if value % 5 == 0 {
s += "Buzz"
}
if s == "" {
s = strconv.Itoa(value)
}
return s
}
// Spin off a Goroutine which will compute the FizzBuzz calculation for the given value
// and return it on the given channel
func asyncCheckFizzBuzz(value int, ch chan string) {
go func() {
ch <- fmt.Sprintf("%s: %s", strconv.Itoa(value), checkFizzBuzz(value));
}()
}
func main() {
// Create the two channels that will be used. One is bound to a goroutine that
// produces numbers in sequence from 1 to 99. This channel has a buffer size of
// zero. That means that when the Goroutine on the other end writes to it,
// that write blocks until the main Goroutine reads from it.
range_ch := intRange(1,100)
// The other is bound to nothing. It will be used to get the results from
// the async FizzBuzz computations.
// This channel has an arbitrarily chosen buffer size of 10, which allows
// writes to it without concurrent reads until the buffer fills.
// Play with this value and see how it changes the output ordering.
result_ch := make(chan string, 10)
// Receive from the number range generator and spin off Goroutines that
// will compute the FizzBuzz calculation.
for i := range range_ch {
asyncCheckFizzBuzz(i, result_ch)
}
// Now, receive values from the FizzBuzz Goroutines and print their results.
// In order to prevent a deadlock, it's necessary have to keep track of how many
// values have been computed so far and stop waiting when there are no more left.
var received int
for v := range result_ch {
received += 1
fmt.Printf("%s\n", v)
if received == 99 {
break
}
}
// Since this channel was created by this main Goroutine, and no other
// Goroutine will close it, it needs to be closed here. This could be
// done thus:
// close(result_ch)
// However, this isn't necessary; the runtime will handle it automatically.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment