golang中time.After一直無法跳出select循環


問題的代碼如下,在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)
	}
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM