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

Why does time.After never fire when it is paired with a ticker in a select block?

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

为什么会这样?

A​​ select 阻塞直到它的一个 case 准备就绪,然后它执行那个 case。在您的示例中 time.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!")
                }   
        }   
}   

关键是,当调用select时,它会在所有情况下重新创建通道子句。如果您在 case <- newCreateTimerChannel 中创建一个计时器,它将启动一个新的计时器。所以把定时器的创建放在for循环之外,让它成为一个全局定时器。