1 回答

TA貢獻1866條經(jīng)驗 獲得超5個贊
前言:使用time.Timer
是推薦的方式,time.After()
這里的使用只是為了演示和推理。請使用第二種方法。
使用time.After()
(不推薦這樣做)
如果你放入time.After()
case 分支,那將在每次迭代中“重置”,因為每次都會返回一個新頻道,這樣就可以了:
func doingSomething(listenCh <-chan string) {
? ? for {
? ? ? ? select {
? ? ? ? case mystr := <-listenCh:
? ? ? ? ? ? log.Println("Received", mystr)
? ? ? ? case <-time.After(1 * time.Second):
? ? ? ? ? ? log.Println("Timeout")
? ? ? ? ? ? return
? ? ? ? }
? ? }
}
(我在 Go Playground 上使用 1 秒超時來提高可測試性。)
我們可以這樣測試它:
ch := make(chan string)
go func() {
? ? for i := 0; i < 3; i++ {
? ? ? ? ch <- fmt.Sprint(i)
? ? ? ? time.Sleep(500 * time.Millisecond)
? ? }
}()
doingSomething(ch)
輸出(在Go Playground上嘗試):
2009/11/10 23:00:00 Received 0
2009/11/10 23:00:00 Received 1
2009/11/10 23:00:01 Received 2
2009/11/10 23:00:02 Timeout
使用time.Timer
(推薦方案)
如果從通道接收的速率很高,這可能會有點浪費資源,因為在后臺創(chuàng)建并使用了一個新計時器,time.After()
它不會神奇地停止并在不再需要時立即收集垃圾如果您在超時前從通道收到一個值。
time.Timer
一個對資源更友好的解決方案是在循環(huán)之前創(chuàng)建一個循環(huán),如果在超時之前收到一個值,則將其重置。
這就是它的樣子:
func doingSomething(listenCh <-chan string) {
? ? d := 1 * time.Second
? ? t := time.NewTimer(d)
? ? for {
? ? ? ? select {
? ? ? ? case mystr := <-listenCh:
? ? ? ? ? ? log.Println("Received", mystr)
? ? ? ? ? ? if !t.Stop() {
? ? ? ? ? ? ? ? <-t.C
? ? ? ? ? ? }
? ? ? ? ? ? t.Reset(d)
? ? ? ? case <-t.C:
? ? ? ? ? ? log.Println("Timeout")
? ? ? ? ? ? return
? ? ? ? }
? ? }
}
測試和輸出是一樣的。在Go Playground試試這個。
- 1 回答
- 0 關(guān)注
- 141 瀏覽
添加回答
舉報