loopsgosleep

Why would I use `case <-time.After(time.Second * 1):` over `time.Sleep(time.Second * 1)` in Golang


Looking through some code I found two ways of doing something every second:

for {
    fmt.Println("This is printed every second")
    time.Sleep(time.Second * 1)
}

and

for {
    select {
    case <-time.After(time.Second * 1):
        fmt.Println("This is printed every second")
    }
}

Apart from the first one being more readable (in my opinion), what are the advantages of one over the other?


Solution

  • There are (at least) two reasons you might want to do that:

    1. time.Sleep always blocks your current goroutine, while waiting on a channel might not if you include a default case:
        timeoutCh := time.After(time.Second)
    LOOP:
        for {
            select {
            case <-timeoutCh:
                break LOOP
            default:
            }
            // do some work
        }
    
    1. You can use it to add a timeout on a long-running operation.
      Let's say your long-running op will notify you on a channel. In that case a timeout on that op would be implemented like this:
        opNotifyCh := op()
        select {
        case res := <-opNotifyCh:
            fmt.Println("Op finished with result:", res)
        case <-time.After(time.Second):
            fmt.Println("Op timed out")
        }
    
    1. time.After gives you a channel. You can do whatever you want with it - you can pass it to a function, you can return it to a caller, you can put it in a struct - anything, really. This gives you a lot of freedom.