首页 >后端开发 >Golang >Go Channels:为什么我的'select”语句中的超时没有触发?

Go Channels:为什么我的'select”语句中的超时没有触发?

DDD
DDD原创
2024-12-26 03:37:09404浏览

Go Channels: Why Doesn't My Timeout in a `select` Statement Ever Trigger?

Go Channels:为什么超时仍未执行

考虑使用 Goroutine 和 Channel 的场景,如下面的代码片段所示。为什么超时场景永远不会发生?

func main() {
    c1 := make(chan int, 1)

    go func() {
        for {
            time.Sleep(1500 * time.Millisecond)
            c1 <- 10
        }
    }()

    go func() {
        for {
            select {
            case i := <-c1:
                fmt.Println(i)
            case <-time.After(2000 * time.Millisecond):
                fmt.Println("TIMEOUT") // Not Executed
            }
        }
    }()

    fmt.Scanln()
}

分析

超时场景不会发生,因为 goroutine 大约每 1.5 秒不断向 c1 通道发送值。只有在 2 秒内没有从 c1 接收到值时,超时才会生效。

但是,当从 c1 接收到值时,一个新的时间。在后续 select 执行中调用后,生成一个新的通道其中仅在另外 2 秒后才会发出值。上一次 select 执行的超时通道将被丢弃,使其无效。

解决方案

要解决此问题,超时通道应该只创建一次,有效:

timeout := time.After(2000 * time.Millisecond)
for {
    select {
    case i := <-c1:
        fmt.Println(i)
    case <-timeout:
        fmt.Println("TIMEOUT") // Will be printed after 2 seconds
    }
}

输出

修改后的代码随后打印:

10
TIMEOUT
10
10
10
...

因此,超时场景现在在 2 后成功执行秒,反映预期行为。

以上是Go Channels:为什么我的'select”语句中的超时没有触发?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn