Using channels for a countdown in Go

I was reading through the Tour of Go and tried to write a small program to check my understanding of channels and select. I was expecting the code snippet below to count down: "5, 4, 3, 2, 1, Blastoff!" However, the program just hangs after "1". Can someone explain what I’m doing wrong?

package main

import (
    "fmt"
    "time"
)

func main() {
    count := time.Tick(100 * time.Millisecond)
    blastoff := make(chan int)

    v := 5
    for {
        select {
        case <-count:
            if v > 0 {
                fmt.Println(v)
                v--
            } else {
                blastoff <- 0
            }
        case <-blastoff:
            fmt.Println("Blastoff!")
            return
        default:
            fmt.Println("...")
            time.Sleep(50 * time.Millisecond)
        }
    }
}

>Solution :

After printing 1, v-- executes and sets v to 0. Next time around when the ticker fires, blastoff<-0 executes. This is an unbuffered channel, so a channel send operation only succeeds if there is another goroutine reading from it. Thus, it blocks there.

An easy fix is making the channel with capacity 1. That way the channel send will work, and it will be received in the next iteration. Or, keep the unbuffered channel, but listen to it in another goroutine.

Leave a Reply