I wanted to try the FizzBuzz test (Why can't programmers program), and used Go. It's basically looping from 1 to 100, and printing "Fizz" when the loop counter is divisible by 3, "Buzz" when divisible by 5, "FizzBuzz" when divisible by both and else just print the number.
After doing it iteratively and recursively, I wanted to do it concurrently (or by using channels). I came up with the following code, which worked to my surprise:
func fizzbuzzconc() {
// Channels for communication
fizzchan := make(chan int)
buzzchan := make(chan int)
fizzbuzzchan := make(chan int)
nonechan := make(chan int)
// Start go routine to calculate fizzbuzz challenge
go func() {
for i := 1; i <= 100; i++ {
if i % 3 == 0 && i % 5 == 0 {
fizzbuzzchan <- i
} else if i % 3 == 0 {
fizzchan <- i
} else if i % 5 == 0 {
buzzchan <- i
} else {
nonechan <- i
}
}
}()
// When or how does this for loop end?
for {
select {
case i := <-fizzchan:
fmt.Println(i, "Fizz")
case i := <-buzzchan:
fmt.Println(i, "Buzz")
case i := <-fizzbuzzchan:
fmt.Println(i, "FizzBuzz")
case i := <-nonechan:
fmt.Println(i, i)
}
}
}
I can't understand how and why the for loop stops. There is no break condition, or a return statement. Why does it eventually finish running?
defaultto your select. Any change? - bishopcaseenter a system call viaPrintln. Go checks channel state during system calls and sees, when the last one empties, that all the channels are done. At that point, it's deadlock detector kicks in and kills the loop. When you add an emptydefault, there's a branch that doesn't go through system calls and go just spins through it. The smallest change you can make to get your code to exit cleanly is to add a wait group channel close in your default case, as seen in this answer: stackoverflow.com/a/21819794/2908724 - bishop