timeout example is unsuitable
kele1997 opened this issue · comments
go-concurrency-patterns/6-select-timeout/main.go
Lines 25 to 35 in 2c16586
We always think timeout
as the time that one service has on response. In this case, timeout
's meaning should be ** we don't receive any message from c
channel for 5 seconds.
so maybe the right code is :
timeout := time.After(5 * time.Second)
for {
select {
case s := <-c:
fmt.Println(s)
timeout = time.After(5 * time.Second) // update timeout time
case <-timeout:
fmt.Println("channel has no response for 5 seconds")
return
}
}
the origin code seems that you want to receive from every channel for same time, like linux cfs scheduler. so maybe in that case we should use ticker
package main
import (
"fmt"
"time"
)
func boring(id int) <-chan string {
c := make(chan string)
go func() {
c <- "" // skip the first time
for i := 0; ; i++ {
c <- fmt.Sprintf("%d, %s", id, time.Now().Format("2006-01-02 15:04:05"))
time.Sleep(1 * time.Second)
}
}()
return c
}
func main() {
timeout := time.NewTicker(5 * time.Second)
c1 := boring(1)
c2 := boring(2)
jobchannels := []<-chan string{c1, c2}
i := 0
for {
select {
case s := <-jobchannels[i]:
fmt.Println(s)
case <-timeout.C:
fmt.Printf("%d has talk for 5 secs\n", i+1)
i = (i + 1) % len(jobchannels)
}
}
}
and it's output is
1, 2021-03-17 11:27:03
1, 2021-03-17 11:27:04
1, 2021-03-17 11:27:05
1, 2021-03-17 11:27:06
1, 2021-03-17 11:27:07
1 has talk for 5 secs
2, 2021-03-17 11:27:08
2, 2021-03-17 11:27:09
2, 2021-03-17 11:27:10
2, 2021-03-17 11:27:11
2, 2021-03-17 11:27:12
2 has talk for 5 secs
1, 2021-03-17 11:27:08
1, 2021-03-17 11:27:14
1, 2021-03-17 11:27:15
1, 2021-03-17 11:27:16
....
I think this example does what it intends to, which is to run for a duration of timeout
from the start , as the select is wrapped in an infinite loop.
If the intention is to give an example of waiting for a fixed timeout for each request(such as get a string from boring goroutine), he will write
for {
select {
case s := <-c:
fmt.Println(s)
case <-time.After(5 * time.Second):
fmt.Println("channel has no response for 5 seconds, you talk too slow")
return
}
}
which does refresh the timer in each select.
inferred from the example code fmt.Println("You talk too much.")
, this is more likely to run for a fixed period of time and
get a bunch of responses before quit, but not an example of timeout for each single request, cause that would happen at the first request, which make the talk too much
part nonsense