Golang中Timer的陷阱

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

Golang的Timer類,是一個普遍意義上的定時器,它有著普通定時器的一些特性,例如:

  • 給定一個到期時間,和一個回呼函數,到期後會調用回呼函數
  • 重設定時器的逾時時間
  • 停止定時器

Golang的Timer在源碼中,實現的方式是以一個小頂堆來維護所有的Timer集合。接著啟動一個獨立的goroutine,迴圈從小頂堆中的檢測最近一個到期的Timer的到期時間,接著它睡眠到最近一個定時器到期的時間。最後會執行開始時設定的回呼函數。Timer到期之後,會被Golang的runtime從小項堆中刪除,並等待GC回收資源。

下面給出實際的代碼:

package mainimport (    "time"    "fmt")func main() {    timer := time.NewTimer(3 * time.Second)    go func() {        <-timer.C        fmt.Println("Timer has expired.")    }()    timer.Stop()    time.Sleep(60 * time.Second)}

timer.NewTimer()會啟動一個新的Timer執行個體,並開始計時。我們啟動一個新的goroutine,來以阻塞的方式從Timer的C這個channel中,等待接收一個值,這個值是到期的時間。並列印”Timer has expired.”

到現在看起來似乎沒什麼問題,但是當我們執行timer.Stop()之後,3秒鐘過去了,程式卻沒有列印那句話。說明執行timer.Stop()之後,Timer內建的channel並沒有關閉,而且這個Timer已經從runtime中刪除了,所以這個Timer永遠不會到期。

這會導致程式邏輯錯誤,或者更嚴重的導致goroutine和記憶體泄露。解決的辦法是,使用timer.Reset()代替timer.Stop()來停止定時器。

package mainimport (    "time"    "fmt")func main() {    timer := time.NewTimer(3 * time.Second)    go func() {        <-timer.C        fmt.Println("Timer has expired.")    }()    //timer.Stop()    timer.Reset(0  * time.Second)    time.Sleep(60 * time.Second)}

這樣做就相當於給Timer一個0秒的逾時時間,讓Timer立刻到期。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.