1. 程式人生 > >golang 中的 time 包的 Ticker

golang 中的 time 包的 Ticker

target spa tro int select con www 結果 div

真實的應用場景是:在測試收包的順序的時候,加了個 tick 就發現丟包了

那麽來看一個應用例子:

package main

import (
    "fmt"
    "runtime"
    "time"
)

func init() {
    runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {
    ch := make(chan int, 1024)
    go func(ch chan int) {
        for {
            val := <-ch
            fmt.Printf(
"val:%d\n", val) } }(ch) tick := time.NewTicker(1 * time.Second) for i := 0; i < 20; i++ { select { case ch <- i: case <-tick.C: fmt.Printf("%d: case <-tick.C\n", i) } time.Sleep(200 * time.Millisecond) } close(ch) tick.Stop() }

輸出結果如下:

val:0
val:1
val:2
val:3
val:4
val:5
6: case <-tick.C
val:7
val:8
val:9
10: case <-tick.C
val:11
val:12
val:13
val:14
15: case <-tick.C
val:16
val:17
val:18
val:19

問題出在這個select裏面:

select {
    case ch <- i:
    case <-tick.C:
      fmt.Printf("%d: case <-tick.C\n", i)
}

  [tick.C 介紹說明] 當兩個 case 條件都滿足的時候,運行時系統會通過一個偽隨機的算法決定哪個case將會被執行。所以當 tick.C 條件滿足的那個循環,有某種概率造成 ch<-i 沒有發送(雖然通道兩端沒有阻塞,滿足發送條件)

 解決方案1:一旦 tick.C 隨機的 case 被隨機到,就多執行一次 ch<-i (不體面,如果有多個case就不通用了)

select {
    case ch <- i:
    case <-tick.C:
        fmt.Printf("%d: case <-tick.C\n", i)
        ch <- i
}

解決方案2:將tick.C的case單獨放到一個select裏面,並加入一個default(保證不阻塞)

select {
    case ch <- i:
}
select {
    case <-tick.C:
        fmt.Printf("%d: case <-tick.C\n", i)
    default:
}

兩種解決方案的輸出都是希望的結果:

val:0
val:1
val:2
val:3
val:4
5: case <-tick.C
val:5
val:6
val:7
val:8
val:9
10: case <-tick.C
val:10
val:11
val:12
val:13
val:14
15: case <-tick.C
val:15
val:16
val:17
val:18
val:19

golang 中的 time 包的 Ticker