深入討論channel timeout

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Go 語言的 channel 本身是不支援 timeout 的,所以一般實現 channel 的讀寫逾時都採用 select,如下:

select {case <-c:case <-time.After(time.Second):}

這兩天在寫碼的過程中突然對這樣實現 channel 逾時產生了懷疑,這種方式真的好嗎?於是我寫了這樣一個測試程式:

package mainimport (    "os"    "time")func main() {    c := make(chan int, 100)    go func() {        for i := 0; i < 10; i++ {            c <- 1            time.Sleep(time.Second)        }        os.Exit(0)    }()    for {        select {        case n := <-c:            println(n)        case <-timeAfter(time.Second * 2):        }    }}func timeAfter(d time.Duration) chan int {    q := make(chan int, 1)    time.AfterFunc(d, func() {        q <- 1        println("run") // 重點在這裡    })    return q}

這個程式很簡單,你會發現運行結果將會輸出 10 次 “run”,也就是每一遍執行 select 註冊的 timer 最終都執行了,雖然這裡讀 channel 都沒有逾時。原因其實很簡單,每次執行 select 語句,都會將 case 條件陳述式給執行一遍,於是 timeAfter 的執行結果就是會建立一個定時器,並註冊到 runtime 中,select 語句執行完成後,這個定時器本身並沒有撤銷,還繼續保留在 runtime 的小頂堆中,所以這些 timer 一逾時就會執行掛載的函數。

當然,用 time.After() 函數來做 channel 的讀寫逾時,在應用程式層根本感受不到底層的定時器還保留著、繼續執行;問題是,如果這裡的 select 語句在迴圈中執行得非常快,也就是 channel 中的訊息來得非常頻繁,會出現的問題就是 runtime 中會有大量的定時器存在,timeout 的時間設定得越長,底層維護的定時器就會越多。原因就是每次 select 都會註冊一個新的 timer,並且 timer 只有在它逾時後才會被刪除。

想想,自己的 channel 每秒鐘將傳輸成千上萬的訊息,將會有多少 timer 對象存在底層 runtime 中。大量的臨時對象會不會影響記憶體?大量的 timer 會不會影響其他定時器的準確度?

最後,我覺得正確的 channel timeout 也許應該這麼做:

to := time.NewTimer(time.Second)for {    to.Reset(time.Second)    select {    case <-c:    case <-to.C:    }}

這樣做就是為了維護一個全域單一的定時器,每次操作前調整一下定時器的逾時時間,從而避免每次迴圈都產生新的定時器對象。

簡單測試了一下兩種 channel 逾時實現方式,在全力收發資料的情況的記憶體對象和 gc 情況。

* 藍線是採用 time.After(),並設定4s 逾時的堆記憶體對象分配的數量* 綠線是採用 time.After(),並設定2s 逾時的堆記憶體對象分配的數量* 黃線是採用全域 timer,並設定4s 逾時的堆記憶體對象分配的數量

這個現象其實是預料之中的,重點可以注意設定的逾時時間越長,time.After() 的表現將越糟糕。



這三條線和的三條線描述的對象是一樣的,圖中的 gc 時間是平均每次 gc 的時間。

針對這個 channel timeout,我沒有去測試是否會影響其他定時器的準確性,但我認為這是必然的,隨著定時器的增多。

最後,我始終覺得 channel 本身應該支援逾時機制,而不是利用 select 來實現。

探索任何一個現象背後的真正原因,才是最有趣的事情。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.