婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Go timer如何調度

Go timer如何調度

熱門標簽:揚州電銷外呼系統軟件 上海企業外呼系統排名 開通400電話申請流程 400手機電話免費辦理 如何利用高德地圖標注家 電腦外呼系統輻射大嗎 智能語音電銷的機器人 武漢百應人工智能電銷機器人 百度地圖標注位置網站

本篇文章剖析下 Go 定時器的相關內容。定時器不管是業務開發,還是基礎架構開發,都是繞不過去的存在,由此可見定時器的重要程度。

我們不管用 NewTimer, timer.After,還是 timer.AfterFun 來初始化一個 timer, 這個 timer 最終都會加入到一個全局 timer 堆中,由 Go runtime 統一管理。

全局的 timer 堆也經歷過三個階段的重要升級。

  • Go 1.9 版本之前,所有的計時器由全局唯一的四叉堆維護,協程間競爭激烈。
  • Go 1.10 - 1.13,全局使用 64 個四叉堆維護全部的計時器,沒有本質解決 1.9 版本之前的問題
  • Go 1.14 版本之后,每個 P 單獨維護一個四叉堆。

Go 1.14 以后的 timer 性能得到了質的飛升,不過伴隨而來的是 timer 成了 Go 里面最復雜、最難梳理的數據結構。本文不會詳細分析每一個細節,我們從大體來了解 Go timer 的工作原理。

1. 使用場景

Go timer 在我們代碼中會經常遇到。

場景1:RPC 調用的防超時處理(下面代碼節選 dubbogo)

func (c *Client) Request(request *remoting.Request, timeout time.Duration, response *remoting.PendingResponse) error {
    _, session, err := c.selectSession(c.addr)
    // .. 省略
    if totalLen, sendLen, err = c.transfer(session, request, timeout); err != nil {
        if sendLen != 0  totalLen != sendLen {
          // .. 省略
        }
        return perrors.WithStack(err)
    }

    // .. 省略
    select {
    case -getty.GetTimeWheel().After(timeout):
        return perrors.WithStack(errClientReadTimeout)
    case -response.Done:
        err = response.Err
    }
    return perrors.WithStack(err)
}

場景2:Context 的超時處理

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()
    go doSomething()
    
    select {
    case -ctx.Done():
        fmt.Println("main", ctx.Err())
    }
}

2. 圖解源碼

2.1 四叉堆原理

timer 的全局堆是一個四叉堆,特別是 Go 1.14 之后每個 P 都會維護著一個四叉堆,減少了 Goroutine 之間的并發問題,提升了 timer 了性能。

四叉堆其實就是四叉樹,Go timer 是如何維護四叉堆的呢?

  • Go runtime 調度 timer 時,觸發時間更早的 timer,要減少其查詢次數,盡快被觸發。所以四叉樹的父節點的觸發時間是一定小于子節點的。
  • 四叉樹顧名思義最多有四個子節點,為了兼顧四叉樹插、刪除、重排速度,所以四個兄弟節點間并不要求其按觸發早晚排序。

這里用兩張動圖簡單演示下 timer 的插入和刪除

把 timer 插入堆

把 timer 從堆中刪除

2.2 timer 是如何被調度的?

調用 NewTimer,timer.After, timer.AfterFunc 生產 timer, 加入對應的 P 的堆上。

調用 timer.Stop, timer.Reset 改變對應的 timer 的狀態。

GMP 在調度周期內中會調用 checkTimers ,遍歷該 P 的 timer 堆上的元素,根據對應 timer 的狀態執行真的操作。

2.3 timer 是如何加入到 timer 堆上的?

把 timer 加入調度總共有下面幾種方式:

  • 通過 NewTimer, time.After, timer.AfterFunc 初始化 timer 后,相關 timer 就會被放入到對應 p 的 timer 堆上。
  • timer 已經被標記為 timerRemoved,調用了 timer.Reset(d),這個 timer 也會重新被加入到 p 的 timer 堆上
  • timer 還沒到需要被執行的時間,被調用了 timer.Reset(d),這個 timer 會被 GMP 調度探測到,先將該 timer 從 timer 堆上刪除,然后重新加入到 timer 堆上
  • STW 時,runtime 會釋放不再使用的 p 的資源,p.destroy()->timer.moveTimers,將不再被使用的 p 的 timers 上有效的 timer(狀態是:timerWaiting,timerModifiedEarlier,timerModifiedLater) 都重新加入到一個新的 p 的 timer 上

2.4 Reset 時 timer 是如何被操作的?

Reset 的目的是把 timer 重新加入到 timer 堆中,重新等待被觸發。不過分為兩種情況:

  • 被標記為 timerRemoved 的 timer,這種 timer 是已經從 timer 堆上刪除了,但會重新設置被觸發時間,加入到 timer 堆中
  • 等待被觸發的 timer,在 Reset 函數中只會修改其觸發時間和狀態(timerModifiedEarlier或timerModifiedLater)。這個被修改狀態的 timer 也同樣會被重新加入到 timer堆上,不過是由 GMP 觸發的,由 checkTimers 調用 adjusttimers 或者 runtimer 來執行的。

2.5 Stop 時 timer 是如何被操作的?

time.Stop 為了讓 timer 停止,不再被觸發,也就是從 timer 堆上刪除。不過 timer.Stop 并不會真正的從 p 的 timer 堆上刪除 timer,只會將 timer 的狀態修改為 timerDeleted。然后等待 GMP 觸發的 adjusttimers 或者 runtimer 來執行。

真正刪除 timer 的函數有兩個 dodeltimer,dodeltimer0。

2.6 Timer 是如何被真正執行的?

timer 的真正執行者是 GMP。GMP 會在每個調度周期內,通過 runtime.checkTimers 調用 timer.runtimer(). timer.runtimer 會檢查該 p 的 timer 堆上的所有 timer,判斷這些 timer 是否能被觸發。

如果該 timer 能夠被觸發,會通過回調函數 sendTime 給 Timer 的 channel C 發一個當前時間,告訴我們這個 timer 已經被觸發了。

如果是 ticker 的話,被觸發后,會計算下一次要觸發的時間,重新將 timer 加入 timer 堆中。

3. Timer 使用中的坑

確實 timer 是我們開發中比較常用的工具,但是 timer 也是最容易導致內存泄露,CPU 狂飆的殺手之一。

不過仔細分析可以發現,其實能夠造成問題就兩個方面:

  • 錯誤創建很多的 timer,導致資源浪費
  • 由于 Stop 時不會主動關閉 C,導致程序阻塞

3.1 錯誤創建很多 timer,導致資源浪費

func main() {
    for {
        // xxx 一些操作
        timeout := time.After(30 * time.Second)
        select {
        case - someDone:
            // do something
        case -timeout:
            return
        }
    }
}

上面這段代碼是造成 timer 異常的最常見的寫法,也是我們最容易忽略的寫法。

造成問題的原因其實也很簡單,因為 timer.After 底層是調用的 timer.NewTimer,NewTimer 生成 timer 后,會將 timer 放入到全局的 timer 堆中。

for 會創建出來數以萬計的 timer 放入到 timer 堆中,導致機器內存暴漲,同時不管 GMP 周期 checkTimers,還是插入新的 timer 都會瘋狂遍歷 timer 堆,導致 CPU 異常。

要注意的是,不只 time.After 會生成 timer, NewTimer,time.AfterFunc 同樣也會生成 timer 加入到 timer 中,也都要防止循環調用。

解決辦法: 使用 time.Reset 重置 timer,重復利用 timer。

我們已經知道 time.Reset 會重新設置 timer 的觸發時間,然后將 timer 重新加入到 timer 堆中,等待被觸發調用。

func main() {
    timer := time.NewTimer(time.Second * 5)    
    for {
        t.Reset(time.Second * 5)

        select {
        case - someDone:
            // do something
        case -timer.C:
            return
        }
    }
}

3.2 程序阻塞,造成內存或者 goroutine 泄露

func main() {
    timer1 := time.NewTimer(2 * time.Second)
    -timer1.C
    println("done")
}

上面的代碼可以看出來,只有等待 timer 超時 "done" 才會輸出,原理很簡單:程序阻塞在 -timer1.C 上,一直等待 timer 被觸發時,回調函數 time.sendTime 才會發送一個當前時間到 timer1.C 上,程序才能繼續往下執行。

不過使用 timer.Stop 的時候就要特別注意了,比如:

func main() {
    timer1 := time.NewTimer(2 * time.Second)
    go func() {
        timer1.Stop()
    }()
    -timer1.C

    println("done")
}

程序就會一直死鎖了,因為 timer1.Stop 并不會關閉 channel C,使程序一直阻塞在 timer1.C 上。

上面這個例子過于簡單了,試想下如果 - timer1.C 是阻塞在子協程中,timer 被的 Stop 方法被調用,那么子協程可能就會被永遠的阻塞在那里,造成 goroutine 泄露,內存泄露。

Stop 的正確的使用方式:

func main() {
    timer1 := time.NewTimer(2 * time.Second)
    go func() {
        if !timer1.Stop() {
            -timer1.C
        }
    }()

    select {
    case -timer1.C:
        fmt.Println("expired")
    default:
    }
    println("done")
}

到此這篇關于Go timer如何調度 的文章就介紹到這了,更多相關Go timer 調度 內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Golang 定時器(Timer 和 Ticker),這篇文章就夠了
  • go語言Timer計時器的用法示例詳解
  • go語言中使用timer的常用方式

標簽:嘉峪關 黑龍江 延邊 武漢 新余 宜賓 張掖 江西

巨人網絡通訊聲明:本文標題《Go timer如何調度》,本文關鍵詞  timer,如何,調度,timer,如何,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Go timer如何調度》相關的同類信息!
  • 本頁收集關于Go timer如何調度的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    www.日韩在线| 国产精品亚洲视频| 日本成人在线电影网| 蜜桃视频在线一区| 一本在线高清不卡dvd| 日韩一区和二区| 国产精品乱码一区二区三区软件| 亚洲女性喷水在线观看一区| 日韩成人dvd| 91视频.com| 精品国产乱码久久久久久1区2区| 国产精品国产自产拍在线| 免费精品99久久国产综合精品| av一区二区三区在线| 精品国产一区二区精华| 亚洲国产一区二区a毛片| 国产成人av电影在线| 911精品国产一区二区在线| 国产精品理伦片| 日本不卡的三区四区五区| 99精品久久只有精品| 欧美电影免费观看高清完整版在| 亚洲欧洲中文日韩久久av乱码| 国产精品夜夜爽| 日韩欧美123| 午夜在线成人av| 色婷婷亚洲综合| 国产日韩精品视频一区| 三级久久三级久久| 欧美色窝79yyyycom| 亚洲欧洲无码一区二区三区| 国产久卡久卡久卡久卡视频精品| 日韩写真欧美这视频| 日日骚欧美日韩| 一本久久a久久精品亚洲| 国产精品麻豆网站| 丁香一区二区三区| 日本一区二区三区在线观看| 国产综合久久久久久久久久久久 | 久久精品欧美一区二区三区不卡| 三级成人在线视频| 欧美午夜精品免费| 伊人开心综合网| 色综合久久中文综合久久97 | 波多野结衣亚洲| 久久无码av三级| 亚洲大型综合色站| 色悠久久久久综合欧美99| 国产精品嫩草影院com| 国产精品18久久久久| www久久精品| 国产一区二区免费看| 欧美一级视频精品观看| 蜜桃免费网站一区二区三区| 在线观看91精品国产麻豆| 午夜视频久久久久久| 欧美精品tushy高清| 亚洲一二三四在线观看| 欧美亚洲日本国产| 一区二区在线观看不卡| 欧美亚洲一区二区在线| 日韩国产欧美视频| 91精品国产乱码久久蜜臀| 日韩成人伦理电影在线观看| 日韩欧美一级二级三级| 国产又黄又大久久| 国产精品三级在线观看| 91麻豆国产在线观看| 一区二区三区四区不卡视频| 一本色道久久综合亚洲精品按摩| 亚洲一区二区三区精品在线| 97精品国产露脸对白| 亚洲精品伦理在线| 在线免费观看日本欧美| 石原莉奈在线亚洲二区| 欧美精品一区二区三区蜜桃视频| 麻豆国产欧美一区二区三区| 日韩午夜在线观看| 九色综合狠狠综合久久| 精品成人一区二区| 国产麻豆精品一区二区| 亚洲欧洲韩国日本视频| 欧美色精品在线视频| 久久国产福利国产秒拍| 欧美国产日本韩| 欧洲在线/亚洲| 日本在线不卡一区| 国产视频911| 91丨porny丨国产| 天天影视网天天综合色在线播放| 欧美一级二级三级蜜桃| 久久99精品国产麻豆婷婷| 国产精品热久久久久夜色精品三区 | 亚洲一区二区三区国产| 日韩免费看的电影| 成人99免费视频| 五月综合激情日本mⅴ| 日韩亚洲电影在线| 99久久精品一区二区| 午夜精品免费在线| 日韩欧美中文字幕精品| 极品销魂美女一区二区三区| 成人欧美一区二区三区白人| 欧美亚洲尤物久久| 国产精品综合一区二区| 亚洲一区二区视频在线| 亚洲精品在线三区| 丁香六月久久综合狠狠色| 亚洲成人av电影在线| 欧美一卡二卡在线观看| 成人av午夜电影| 日韩成人精品视频| 亚洲人成网站影音先锋播放| 91在线精品秘密一区二区| 天天av天天翘天天综合网 | 国产精品色哟哟| 91免费观看视频在线| 极品销魂美女一区二区三区| 亚洲在线视频免费观看| 久久久久成人黄色影片| 99精品热视频| 午夜精品一区二区三区免费视频| 欧美国产精品一区| 色婷婷久久久久swag精品| 日韩福利电影在线| 亚洲精品一二三四区| 日韩三级高清在线| 色婷婷国产精品综合在线观看| 久久97超碰色| 亚洲va天堂va国产va久| 国产丝袜欧美中文另类| 日韩你懂的在线播放| 欧美日韩国产欧美日美国产精品| 国产精品热久久久久夜色精品三区| 色香蕉成人二区免费| 久久精品国产99久久6| 亚洲成人av中文| 最好看的中文字幕久久| 精品剧情在线观看| 欧美日韩综合色| 色一情一伦一子一伦一区| 成人91在线观看| 国产ts人妖一区二区| 精品亚洲成a人| 欧美a级理论片| 亚洲三级理论片| 国产精品国产三级国产普通话99| 久久久久综合网| 精品久久人人做人人爰| 色婷婷av一区二区三区之一色屋| 成人av第一页| 成人精品视频网站| 国产一区二区三区不卡在线观看| 免费成人在线观看| 日本中文在线一区| 日本欧美一区二区在线观看| 亚洲一区二区3| 亚洲成人av在线电影| 亚洲第一福利一区| 亚洲欧洲韩国日本视频| 亚洲日本在线观看| 国产精品久线在线观看| 中文字幕的久久| 欧美成人精品3d动漫h| 日韩一区二区视频| 91精品国产综合久久福利| 欧美酷刑日本凌虐凌虐| 欧美性受xxxx黑人xyx性爽| 色婷婷精品久久二区二区蜜臀av| 色婷婷亚洲精品| 91国偷自产一区二区开放时间| 91蝌蚪porny成人天涯| 成人黄色在线网站| 99国产一区二区三精品乱码| 国产成人亚洲综合a∨婷婷图片| 国产精品正在播放| 久久 天天综合| 国产成人av福利| 精品一区二区精品| 国产成人aaa| 91在线你懂得| 欧美在线999| 欧美日产国产精品| 欧美日韩国产免费| 在线电影一区二区三区| 欧美日韩午夜精品| 欧美美女一区二区三区| 欧美精品久久久久久久多人混战| 欧美日韩dvd在线观看| 日韩一区二区三区精品视频| 91精品国产91热久久久做人人| 9191久久久久久久久久久| 日韩欧美视频在线 | 国内精品国产成人| 久久99国产精品免费网站| 国产ts人妖一区二区| 91美女片黄在线观看91美女| 欧美在线观看禁18| 日韩精品一区二区三区中文精品| 久久亚洲二区三区|