我正在使用time.Ticker一些阻塞代碼,發現一個奇怪的行為:
func main() {
ticker := time.NewTicker(1 * time.Second)
i := 0
for {
select {
case <-ticker.C:
log.Println(i)
if i == 0 {
time.Sleep(5 * time.Second) // simulate the blocking
}
i
}
}
}
示例輸出:
2022/02/20 10:49:45 0
2022/02/20 10:49:50 1 <- shows at same time
2022/02/20 10:49:50 2 <- shows at same time
2022/02/20 10:49:51 3
2022/02/20 10:49:52 4
2022/02/20 10:49:53 5
...
“1”和“2”總是同時顯示,這是為什么呢?
uj5u.com熱心網友回復:
代碼創建一個容量為 1的緩沖通道。當通道已滿時,自動收報機會丟棄時間值。
這是問題中跟蹤的時間表。同一時間列出的事件按列出的順序依次發生一點點。
1s - ticker sends value
1s - main goroutine receives first value
1s - main goroutine starts sleep for 5s
2s - ticker sends value (channel has capacity 1).
3s - ticker fails to send value because channel is full
4s - ticker fails to send value because channel is full
5s - ticker fails to send value because channel is full
6s - main goroutine exits sleep and receives buffered value
6s - ticker sends value
6s - main goroutine receives buffered value
ticker 和 main goroutine 跑到 6s 標記,因為 sleep 是 ticker 周期的倍數。在您的跟蹤中,主 goroutine 贏得了比賽。在我的機器上,自動收報機贏得了比賽,我得到了你期望的時間。這是我機器上的樣子。
...
5s - ticker fails to send value because channel is full
6s - ticker fails to send value because channel is full
6s - main goroutine receives buffered value
7s - ticker sends value
7s - main goroutine receives value
自動收報機在操場上以 6 秒的成績贏得比賽。 在這里運行它。當睡眠時間減少 1μs 時,主 goroutine 贏得了比賽。在這里運行它。
當睡眠持續時間不是代碼周期的倍數時,這很容易看出。以下是睡眠持續時間為 2.5 秒時發生的情況:
1s - ticker sends value
1s - main goroutine receives first value
1s - main goroutine starts sleep for 2.5s
2s - ticker sends value
3s - ticker fails to send value because channel is full
3.5s - main goroutine exits sleep and receives buffered value
4s - ticker sends value
4s - main goroutine receives value
在操場上運行最后一個示例。
uj5u.com熱心網友回復:
在time.Ticker中,有一個chan Time. 在NewTicker(d Duration) *Ticker函式中,它創建tickers時間通道作為容量為1的緩沖通道。在函式中,如下所述。
// 給通道一個 1 元素的時間緩沖區。
// 如果客戶在閱讀時落后了,我們將滴答聲
// 放在地板上,直到客戶趕上。
在您的情況下,時間每秒都會滴答并寫入頻道。睡眠時,ticker 向通道寫入一次,回圈繼續后立即被 select case 接收并列印。在另外 4 秒內,通道被阻塞并且滴答聲被丟棄。立即回圈繼續它被暢通并接受更多的通道滴答聲。
通過通道列印時間,您可以輕松了解行為。更新代碼如下。
func main() {
ticker := time.NewTicker(1 * time.Second)
i := 0
for {
select {
case t := <-ticker.C:
log.Println(i, t)
if i == 0 {
time.Sleep(5 * time.Second) // simulate the blocking
}
i
}
}
}
輸出:
2022/02/20 08:47:58 0 2022-02-20 08:47:58.773375 0530 0530 m= 1.004241004
2022/02/20 08:48:03 1 2022-02-20 08:47:59.772787 0530 0530 m= 2.003666993
2022/02/20 08:48:03 2 2022-02-20 08:48:03.774272 0530 0530 m= 6.005207433 // printing time is same, but channel's received time has 4 sec difference.
2022/02/20 08:48:04 3 2022-02-20 08:48:04.774203 0530 0530 m= 7.005151715
在操場上奔跑。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/429821.html
上一篇:使用pgx和go在簡單的postgresql查詢中回傳id
下一篇:從切片呼叫函式名并回傳一個值
