問題的代碼如下,在for select 循環中,本想通過 time.After 設置超時時間,但一直無法退出。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
ch := make(chan int)
go func() {
for v := range ch {
fmt.Println(v)
}
}()
END:
for {
select {
case ch <- rand.Int():
case <-time.After(time.Second * 3):
fmt.Println("timeout")
break END
}
time.Sleep(time.Second)
}
}
控制台始終打印出從通道 ch 中讀取的隨機數,time.After 一直沒能等到。
原因是每次進入到 case <-time.After(time.Second * 3): 時,都會創建一個新的通道返回,所以這個 case 每次都在等待接收新的通道的數據,永遠不可能等到。
time.After 方法的源碼如下:
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
每次調用都會通過 NewTimer 創建一個新的 Timer,並且 Timer.C 也是新創建的通道。
func NewTimer(d Duration) *Timer {
c := make(chan Time, 1)
t := &Timer{
C: c,
r: runtimeTimer{
when: when(d),
f: sendTime,
arg: c,
},
}
startTimer(&t.r)
return t
}
為了解決上面的問題,我們可以把 time.After 放在 for 循環外面,來解決此問題。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
ch := make(chan int)
timer := time.After(time.Second * 3)
go func() {
for v := range ch {
fmt.Println(v)
}
}()
END:
for {
select {
case ch <- rand.Int():
case <-timer:
fmt.Println("timeout")
break END
}
time.Sleep(time.Second)
}
}
