Everton
Everton

Reputation: 13825

Why doesn't this Golang code to select among multiple time.After channels work?

Why doesn't this Golang code to select among multiple time.After channels work?

See code below. The 'timeout' message is never issued. Why?

package main

import (
    "fmt"
    "time"
)

func main() {
    count := 0
    for {
        select {
        case <-time.After(1 * time.Second):
            count++
            fmt.Printf("tick %d\n", count)
            if count >= 5 {
                fmt.Printf("ugh\n")
                return
            }
        case <-time.After(3 * time.Second):
            fmt.Printf("timeout\n")
            return
        }
    }
}

Run it on Playground: http://play.golang.org/p/1gku-CWVAh

Output:

tick 1
tick 2
tick 3
tick 4
tick 5
ugh

Upvotes: 12

Views: 3774

Answers (2)

Endre Simo
Endre Simo

Reputation: 11551

Even @Ainar-G has already provided the answer, another possibility is to use time.Tick(1e9) to generate a time tick on every second and then listen for timeAfterchannel after the specified period.

package main

import (
    "fmt"
    "time"
)

func main() {
    count := 0
    timeTick := time.Tick(1 * time.Second)
    timeAfter := time.After(5 * time.Second)

    for {
        select {
        case <-timeTick:
            count++
            fmt.Printf("tick %d\n", count)
            if count >= 5 {
                fmt.Printf("ugh\n")
                return
            }
        case <-timeAfter:
            fmt.Printf("timeout\n")
            return
        }
    }
}

Upvotes: 5

Ainar-G
Ainar-G

Reputation: 36189

Because time.After is a function, so on every iteration it returns a new channel. If you want this channel to be the same for all iterations, you should save it before the loop:

timeout := time.After(3 * time.Second)
for {
    select {
    //...
    case <-timeout:
        fmt.Printf("timeout\n")
        return
    }
}

Playground: http://play.golang.org/p/muWLgTxpNf.

Upvotes: 19

Related Questions