Golang频道:超时模式不起作用

时间:2019-01-27 09:36:37

标签: go channel

我尝试为我的项目实施Timeout pattern。这是上面链接的示例代码:

c1 := make(chan string, 1)
go func() {
    time.Sleep(2 * time.Second)
    c1 <- "result 1"
}()

select {
case res := <-c1:
    fmt.Println(res)
case <-time.After(1 * time.Second):
    fmt.Println("timeout 1")
}

另一个例子是:

c2 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "result 2"
    }()
    select {
    case res := <-c2:
        fmt.Println(res)
    case <-time.After(3 * time.Second):
        fmt.Println("timeout 2")
    }

我可以成功运行此示例。然后,我尝试将其应用于我的项目。这是我的项目代码:

for {
    select {
    case ev := <-c.EventChannel():
        // do something here
    case <-time.After(2 * time.Second):
        // this condition never happend
        return
    default:
       // do nothing as non-blocking channel pattern
    }
}

但是我不知道为什么代码永远不会遇到超时情况。当我将time.After(2 * time.Second)移到单独的语句中时,它可以工作。这是修改后的代码:

timeout := time.After(2 * time.Second)
for {
    select {
    case ev := <-c.EventChannel():
        // do something here
    case <-timeout:
        require.Equal(t, "time out after 2s", "")
    default:
        // do nothing as non-blocking channel pattern
    }
}

我不知道2个案例之间的区别。以及为什么第一个示例可行。请帮我弄清楚。

谢谢

1 个答案:

答案 0 :(得分:3)

基本上,如果有默认情况,select语句将不会等待,因此在您的情况下,它仅检查EventChannel并转为默认情况,因为它没有阻塞并且不会等待2 seconds timeout。在每次迭代中,都有2 secs超时,因此它永远不会执行。

在第二种情况下,由于计时器不在循环中,因此它不会在每次迭代中重新初始化,因此在2 seconds select语句之后,它将捕获该信号并执行超时。

如果您想在每次迭代中等待2 secs,则可以执行以下操作

for {
  select {
  case ev := <-c.EventChannel():
      // do something here
  default:
      // do nothing as non-blocking channel pattern
  }
  time.Sleep(2 *time.Second)

}