为什么 time.After 与选择块中的代码配对时永远不会触发?

我有一个正在监听 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!")

        }

    }

}

为什么会这样?


千巷猫影
浏览 182回答 2
2回答

白猪掌柜的

Aselect阻塞,直到它的一个案例准备好,然后它执行那个案例。在您的示例中 time.After() 永远不会被调用。func main() {&nbsp; &nbsp; ticker := time.NewTicker(5 * time.Second)&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case z := <-ticker.C:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("tick %d\n", z)&nbsp; &nbsp; &nbsp; &nbsp; //This never gets chance to be ready. It'll work if you make it less than 5 seconds.&nbsp; &nbsp; &nbsp; &nbsp; case <-time.After(12 * time.Second):&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("12 seconds elapsed!")&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}您可以通过在for循环之前声明计时器来使其工作。func main() {&nbsp; &nbsp; &nbsp; &nbsp; ticker := time.NewTicker(5 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; timer := time.After(12 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case z := <-ticker.C:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("tick %d\n", z)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-timer:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("12 seconds elapsed!")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp;}&nbsp; &nbsp;

拉丁的传说

关键是,当调用 select 时,它将在所有 case 子句中重新创建通道。如果您在 中创建计时器case <- newCreateTimerChannel,它将启动一个新计时器。所以把定时器的创建放在for循环之外,让它成为一个全局定时器。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go