Trần Kim Dự
Trần Kim Dự

Reputation: 6102

Golang channel: timeout pattern not work as example

I try to implement Timeout pattern for my project. Here is an example code of above link:

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")
}

Another example is:

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")
    }

I can run this example successfully. Then I try apply this to my project. Here is my project code:

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
    }
}

But I don't know why code never run into timeout case. When I move time.After(2 * time.Second) into separate statement, it works. Here is modified code:

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
    }
}

I don't know the differences between 2 cases. And why first example works. Please help me figure out.

Thanks

Upvotes: 0

Views: 1487

Answers (1)

Shettyh
Shettyh

Reputation: 1216

Basically the select statement wont wait if there is a default case, so in your case it just checks for EventChannel and goes to default case because it is not blocking and it wont wait for 2 seconds timeout. In every iteration there is a 2 secs timeout , so it never get executed.

In the second case as the timer is outside the loop it wont reinitialize in each iteration so after 2 seconds select statement will catch that signal and executes timeout.

If you want to wait for 2 secs in each iteration then you can do something like this

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

}

Upvotes: 3

Related Questions