最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

go?time.After優(yōu)化后性能提升34%內(nèi)存減少67%

 更新時間:2023年02月24日 14:39:00   作者:steden  
這篇文章主要介紹了go語言time.After優(yōu)化后性能提升34%內(nèi)存減少67%實例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

大家好,今天給大家?guī)硪黄绾蝺?yōu)化time.After函數(shù)。

最近我在做調(diào)度中心2.0的重構。本次重構使用的GO語言開發(fā)。

在項目中,基本都離不開需要休眠等待一定時間后再執(zhí)行下一步邏輯的操作,再搭配select,用起來是真的舒服。

func waitWorking() {
    select {
    case <-time.After(5 * time.Second): // 每隔5秒,主動向客戶端詢問任務狀態(tài)
        _ = receiver.CheckWorkingEventBus.Publish(receiver)
    case <-receiver.updated:
    }
}

在這個示例中,5秒后會執(zhí)行Publish函數(shù),或者<-receiver.updated有數(shù)據(jù)時退出,這是我們比較常用的方式。

但有一點要注意的是:time.After如果沒有被執(zhí)行到,會導致無法第一時間GC回收內(nèi)存。

從內(nèi)存分析中,會看到內(nèi)存在持續(xù)增長,到了一定時間后,才會下降。這個增長幅度隨著你的項目請求量而決定。

這是因為當<-receiver.updated被觸發(fā)執(zhí)行時,導致time.After(5 * time.Second)在5秒后才會有數(shù)據(jù)進來,在這5秒內(nèi),time.After創(chuàng)建的NewTimer(d)是無法回收的。

func After(d Duration) <-chan Time {
    return NewTimer(d).C
}

明白了這一點之后,我們可以簡單的做一個改進

改進1:

func waitWorking() {
    timer := time.NewTimer(5 * time.Second)
    select {
    case <-timer.C: // 每隔5秒,主動向客戶端詢問任務狀態(tài)
        _ = receiver.CheckWorkingEventBus.Publish(receiver)
    case <-receiver.updated:
        timer.Stop()
    }
}

<-receiver.updated被觸發(fā)執(zhí)行時,我們主動調(diào)用Stop方法,來告知GC,此timer對象不再使用。

這樣就不至于等到5秒后,GC才知道這個對象不再使用。

這就完了嗎?顯示沒有,如果waitWorking函數(shù)會在并發(fā)中被調(diào)用:

type TaskGroupMonitor struct {
    updated chan struct{}   // 數(shù)據(jù)有更新,讓流程重置
   name    string          // 任務名稱
}
func (receiver *TaskGroupMonitor) waitWorking() {
    timer := time.NewTimer(5 * time.Second)
    select {
    case <-timer.C: // 每隔5秒,主動向客戶端詢問任務狀態(tài)
        _ = receiver.CheckWorkingEventBus.Publish(receiver)
    case <-receiver.updated:
        timer.Stop()
    }
}

func init() {
   // 模擬數(shù)據(jù)庫讀到了100條任務
    for i := 0; i < 100; i++ {
      taskGroup:= TaskGroupMonitor{}
        go taskGroup.waitWorking()
    }
}

這里假如從數(shù)據(jù)庫中讀到了100條任務數(shù)據(jù),每條數(shù)據(jù)都在獨立的協(xié)程中運行。

這就會導致在這100條任務在運行的過程中,創(chuàng)建了100個time.Timer對象,事實上除了waitWorking,還會有waitStart,waitScheduler,taskFinish等函數(shù)也使用了time.Timer對象。

可以想到,項目在運行過程中time.Timer在不停的創(chuàng)建,直到GC后才被回收。這將導致我們的內(nèi)存一直占用著。

并且time.Aftertime.NewTicker并不是高精度的時間控制。有時候會慢那么0-3ms,協(xié)程數(shù)量越多越繁忙,則越不精準。

這對于調(diào)度中心而言是無法接收的,我的目標是支持幾千個任務同時監(jiān)控調(diào)度。意味著協(xié)程數(shù)量會非常高。

而在GO的time.Timer中是使用64個timersBucket,并使用四叉堆來管理各個timer,雖然在1.17版本有所改進。

但時間上仍然沒有那么準確,對于調(diào)度這種場景來說,對ms級別的延遲也是沒辦法接受的。

time.Timer原理不在本篇的范圍內(nèi),現(xiàn)在有很多大神有這方面的剖析,感興趣可以去搜搜。

分析問題

通過簡單的分析,我們已經(jīng)知道使用time.Timer會有如下缺點:

  • 每個協(xié)程需要創(chuàng)建time.Timer(導致內(nèi)存占用上升)
  • time.Timer會有延遲(對于ms敏感的場景不適用)

即如此,我們是否可以通過統(tǒng)一的時間管理器來管理所有的時間觸發(fā)器呢?

答案是顯而易見的,那就是時間輪。

時間輪

時間輪是一種實現(xiàn)延遲功能的算法, 它在Linux內(nèi)核中使用廣泛, 是Linux內(nèi)核定時器的實現(xiàn)方法和基礎之一. 時間輪是一種高效來利用線程資源來進行批量化調(diào)度的一種調(diào)度模型, 把大量的調(diào)度任務全部綁定到同一個調(diào)度器上, 利用這個調(diào)度器來進行所有任務的管理, 觸發(fā)以及運行.

簡單來說,時間輪就是一個模擬時鐘的原理。 實現(xiàn)方式有:單層、雙層、多層三種方式。

而在雙層、多層時間輪中,又有兩種算法:一種是不管幾層,時間周期是一樣的。另一種是低層一圈 = 上層一格(像秒針、分針一樣)

在時鐘里,秒針走完一圈,分針走一格。分針走完一圈,時針走一格。以此類推。

當秒針走到第X格,會到第X格的隊列中找到是否有待執(zhí)行任務列表,如果有則取出并通知到C變量。

而我在實現(xiàn)這個時間輪就是完全模擬時鐘的這種算法來實現(xiàn)的。我與其它開源的時間輪不一樣的地方是,我是高精度算法的。

時間輪的原理大概就講這么多,畢竟不是一個什么新鮮的算法,網(wǎng)上有很多講的比我更透徹的大神,在這里我主要講使用時間輪的前后對比。

我們來看看如何使用:

// 在項目中,定義一個全局變量tw,并規(guī)定第0層,走一格=100ms,一圈有120格
import "github.com/farseer-go/fs/timingWheel"

var tw = timingWheel.New(100*time.Millisecond, 120)
tw.Start()

接著在項目中我們改成時間輪來控制時間:

func (receiver *TaskGroupMonitor) waitWorking() {
   select {
   case &lt;-tw.AddPrecision(60 * time.Second).C:
        _ = receiver.CheckWorkingEventBus.Publish(receiver)
   case &lt;-receiver.updated:
   }
}

至此,我們使用了全局tw變量來控制時間的延遲管理。

我們來看下,優(yōu)化前的情況:

100個并發(fā)下調(diào)度:平均延遲:10ms、CPU:31.4%、內(nèi)存:115m

優(yōu)化后:

100個并發(fā)下調(diào)度:平均延遲:1ms、CPU:21.7%、內(nèi)存:34.5m

為此,整體性能提升:34%,內(nèi)存減少:67%

相關材料:

以上就是go time.After優(yōu)化后性能提升34%內(nèi)存減少67%的詳細內(nèi)容,更多關于go time.After優(yōu)化性能內(nèi)存的資料請關注腳本之家其它相關文章!

相關文章

  • golang 流式讀取和發(fā)送使用場景示例

    golang 流式讀取和發(fā)送使用場景示例

    這篇文章主要為大家介紹了golang 流式讀取和發(fā)送使用場景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Golang 運算符及位運算詳解

    Golang 運算符及位運算詳解

    這篇文章主要介紹了Golang 運算符及位運算詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • GoLang逃逸分析講解

    GoLang逃逸分析講解

    我們都知道go語言中內(nèi)存管理工作都是由Go在底層完成的,這樣我們可以不用過多的關注底層的內(nèi)存問題。本文主要總結一下?Golang內(nèi)存逃逸分析,需要的朋友可以參考以下內(nèi)容,希望對大家有幫助
    2022-12-12
  • go-cqhttp環(huán)境配置及安裝過程

    go-cqhttp環(huán)境配置及安裝過程

    這篇文章主要介紹了go-cqhttp環(huán)境配置,包括go-cqhttp安裝及簡單介紹,本文結合示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • golang基礎之Interface接口的使用

    golang基礎之Interface接口的使用

    這篇文章主要介紹了golang基礎之Interface接口的使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • go語言版的ip2long函數(shù)實例

    go語言版的ip2long函數(shù)實例

    這篇文章主要介紹了go語言版的ip2long函數(shù),實例分析了Go語言實現(xiàn)的ip2long函數(shù)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • Go語言基礎設計模式之策略模式示例詳解

    Go語言基礎設計模式之策略模式示例詳解

    這篇文章主要為大家介紹了Go語言基礎設計模式之策略模式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2021-11-11
  • Golang 基礎之函數(shù)使用(匿名遞歸閉包)實例詳解

    Golang 基礎之函數(shù)使用(匿名遞歸閉包)實例詳解

    這篇文章主要為大家介紹了Golang 基礎之函數(shù)使用(匿名遞歸閉包)實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Golang中的錯誤處理的示例詳解

    Golang中的錯誤處理的示例詳解

    這篇文章主要為大家詳細介紹了Golang中的錯誤處理的相關資料,文章中的示例代碼講解詳細,對我們學習Golang有一定幫助,需要的可以參考一下
    2022-12-12
  • 解決Golang 中使用WaitGroup的那點坑

    解決Golang 中使用WaitGroup的那點坑

    這篇文章主要介紹了解決Golang 中使用WaitGroup的那點坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04

最新評論

汝城县| 永泰县| 莫力| 东乌珠穆沁旗| 绵阳市| 惠州市| 平乡县| 洛南县| 潜山县| 宁津县| 阿尔山市| 宁波市| 陆川县| 聂拉木县| 黄龙县| 商河县| 安龙县| 怀柔区| 林甸县| 青铜峡市| 崇义县| 遵义市| 襄城县| 盱眙县| 武宁县| 基隆市| 保定市| 黔西县| 广汉市| 曲阜市| 淮阳县| 喀喇沁旗| 额尔古纳市| 驻马店市| 张掖市| 赣州市| 尚义县| 新泰市| 华蓥市| 白水县| 公主岭市|