第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Go 的 once 類型的效率測量

Go 的 once 類型的效率測量

Go
瀟瀟雨雨 2023-05-08 17:54:55
我有一段代碼,我只想運行一次以進行初始化。到目前為止,我使用 sync.Mutex 結合 if 子句來測試它是否已經運行。后來我在同一個同步包中遇到了 Once 類型及其 DO() 函數。實現如下https://golang.org/src/sync/once.go:func (o *Once) Do(f func()) {    if atomic.LoadUint32(&o.done) == 1 {        return    }    // Slow-path.    o.m.Lock()    defer o.m.Unlock()    if o.done == 0 {        defer atomic.StoreUint32(&o.done, 1)        f()    }}查看代碼,它基本上是我之前一直在使用的相同的東西。與 if 子句結合的互斥量。但是,添加的函數調用使我覺得這看起來效率很低。我做了一些測試并嘗試了各種版本:func test1() {    o.Do(func() {        // Do smth    })    wg.Done()}func test2() {    m.Lock()    if !b {        func() {            // Do smth        }()    }    b = true    m.Unlock()    wg.Done()}func test3() {    if !b {        m.Lock()        if !b {            func() {                // Do smth            }()            b = true        }        m.Unlock()    }    wg.Done()}我通過運行以下代碼測試了所有版本:    wg.Add(10000)    start = time.Now()    for i := 0; i < 10000; i++ {        go testX()    }    wg.Wait()    end = time.Now()    fmt.Printf("elapsed: %v\n", end.Sub(start).Nanoseconds())結果如下:elapsed: 8002700 //test1elapsed: 5961600 //test2elapsed: 5646700 //test3甚至值得使用 Once 類型嗎?它很方便,但性能甚至比始終序列化所有例程的 test2 更差。另外,為什么他們在 if 子句中使用 atomic int?無論如何,存儲都發(fā)生在鎖內。編輯:Go playground 鏈接:https://play.golang.org/p/qlMxPYop7kS注意:這不會顯示結果,因為 playground 的時間是固定的。
查看完整描述

1 回答

?
繁星點點滴滴

TA貢獻1803條經驗 獲得超3個贊

那不是您應該測試代碼性能的方式。您應該使用 Go 的內置測試框架(testing包和go test命令)。

讓我們創(chuàng)建可測試代碼:

func f() {

? ? // Code that must only be run once

}


var testOnce = &sync.Once{}


func DoWithOnce() {

? ? testOnce.Do(f)

}


var (

? ? mu = &sync.Mutex{}

? ? b? bool

)


func DoWithMutex() {

? ? mu.Lock()

? ? if !b {

? ? ? ? f()

? ? ? ? b = true

? ? }

? ? mu.Unlock()

}

讓我們使用該testing包編寫適當的測試/基準測試代碼:


func BenchmarkOnce(b *testing.B) {

? ? for i := 0; i < b.N; i++ {

? ? ? ? DoWithOnce()

? ? }

}


func BenchmarkMutex(b *testing.B) {

? ? for i := 0; i < b.N; i++ {

? ? ? ? DoWithMutex()

? ? }

}

我們可以使用以下代碼運行基準測試:


go test -bench .

以下是基準測試結果:


BenchmarkOnce-4? ? ? ? ?200000000? ? ? ? ? ? ? ? 6.30 ns/op

BenchmarkMutex-4? ? ? ? 100000000? ? ? ? ? ? ? ?20.0 ns/op

PASS

如您所見,使用sync.Once()比使用sync.Mutex. 為什么?因為sync.Once()有一個“優(yōu)化”的短路徑,它只使用原子加載來檢查任務之前是否被調用過,如果是,則不使用互斥鎖。“慢速”路徑可能只在第一次調用Once.Do(). 雖然如果你有許多并發(fā)的 goroutines 試圖調用DoWithOnce(),慢速路徑可能會多次到達,但從長遠來看once.Do()只需要使用原子負載。


并行測試(來自多個 goroutines)

是的,上面的基準測試代碼僅使用單個 goroutine 進行測試。但是使用多個并發(fā) goroutine 只會讓互斥體的情況變得更糟,因為它總是必須獲得一個互斥體來檢查是否要調用任務,而只sync.Once使用原子負載。


盡管如此,讓我們對其進行基準測試。


以下是使用并行測試的基準測試代碼:


func BenchmarkOnceParallel(b *testing.B) {

? ? b.RunParallel(func(pb *testing.PB) {

? ? ? ? for pb.Next() {

? ? ? ? ? ? DoWithOnce()

? ? ? ? }

? ? })

}


func BenchmarkMutexParallel(b *testing.B) {

? ? b.RunParallel(func(pb *testing.PB) {

? ? ? ? for pb.Next() {

? ? ? ? ? ? DoWithMutex()

? ? ? ? }

? ? })

}

我的機器上有 4 個內核,所以我將使用這 4 個內核:


go test -bench Parallel -cpu=4

(您可以省略該-cpu標志,在這種情況下,它默認為GOMAXPROCS– 可用核心數。)


結果如下:


BenchmarkOnceParallel-4? ? ? ? ?500000000? ? ? ? ? ? ? ? 3.04 ns/op

BenchmarkMutexParallel-4? ? ? ? 20000000? ? ? ? ? ? ? ? 93.7 ns/op

當“并發(fā)增加”時,結果開始變得無與倫比sync.Once(在上面的測試中,它快了 30 倍)。


我們可能會進一步增加使用創(chuàng)建的 goroutines 的數量testing.B.SetPralleism(),但是當我將它設置為 100 時我得到了類似的結果(這意味著 400 個 goroutines 被用來調用基準測試代碼)。


查看完整回答
反對 回復 2023-05-08
  • 1 回答
  • 0 關注
  • 170 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號