为什么是时间。在选择区块中与自动收报机配对后从不开火?

时间:2016-06-08 01:26:35

标签: go timer ticker

我有一个正在监听2个频道的选择块,一个自动收报机和一个计时器:

package main

import (
    "fmt"
    "time"
)

func main() {

    ticker := time.NewTicker(5 * time.Second)
    for {
        select {
        case z := <-ticker.C:
            fmt.Printf("tick %d\n", z)

        case <-time.After(12 * time.Second):
            fmt.Println("12 seconds elapsed!")
        }
    }
}

如果我运行代码,time.After案例永远不会运行,但代码工作正常。

如果我删除了代码,time.After会正确触发:

package main

import (
    "fmt"
    "time"
)

func main() {

    for {
        select {
        case <-time.After(12 * time.Second):
            fmt.Println("12 seconds elapsed!")
        }
    }
}

如果我使用计时器而不是time.After

,它可以正常工作
package main

import (
    "fmt"
    "time"
)

func main() {

    ticker := time.NewTicker(5 * time.Second)
    timer := time.NewTimer(12 * time.Second)
    for {
        select {
        case z := <-ticker.C:
            fmt.Printf("tick %d\n", z)

        case <-timer.C:
            fmt.Println("12 seconds elapsed!")
        }
    }
}

为什么会这样?

2 个答案:

答案 0 :(得分:4)

select阻塞直到其中一个案例准备就绪,然后执行该案例。在你的例子中.After()永远不会被调用。

func main() {

    ticker := time.NewTicker(5 * time.Second)
    for {
        select {
        case z := <-ticker.C:
            fmt.Printf("tick %d\n", z)

        //This never gets chance to be ready. It'll work if you make it less than 5 seconds.
        case <-time.After(12 * time.Second): 
            fmt.Println("12 seconds elapsed!")
        }
    }
}

您可以通过在for循环之前声明计时器来使其正常工作。

func main() {

        ticker := time.NewTicker(5 * time.Second)
        timer := time.After(12 * time.Second)
        for {
                select {
                case z := <-ticker.C:
                        fmt.Printf("tick %d\n", z)

                case <-timer:
                        fmt.Println("12 seconds elapsed!")
                }   
        }   
}   

答案 1 :(得分:1)

关键是,当调用select时,它将在所有case子句中重新创建通道。如果您在case <- newCreateTimerChannel中创建一个计时器,它将启动一个新计时器。因此,将计时器创建内容置于for循环之外,以使其成为全局计时器。