首頁 > 後端開發 > Golang > 主體

為什麼 Go 的 `sync.Once` 使用 `atomic.StoreUint32` 而不是普通的賦值來設定 `done` 標誌?

Patricia Arquette
發布: 2024-10-31 10:48:02
原創
901 人瀏覽過

Why does Go's `sync.Once` use `atomic.StoreUint32` instead of normal assignment to set the `done` flag?

Go 的sync.Once 中原子操作的正確使用

在Go 的sync.Once 實現的上下文中,了解以下內容至關重要:設定done標誌時普通賦值與atomic.StoreUint32操作之間的差異。

不正確的實作

最初,once.go中的Do函數使用了以下方法:

if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
    f()
}
登入後複製

此實作無法保證在Do 回傳時f 的執行完成。對 Do 的兩個並發呼叫可能會導致第一個呼叫成功呼叫 f,而第二個呼叫過早返回,認為 f 已完成,即使它尚未完成。

原子儲存操作

為了解決這個問題,Go 使用了atomic.StoreUint32 操作。與普通賦值不同,atomic.StoreUint32 確保更新後的完成標誌對其他 goroutine 的可見度。

記憶體模型注意事項

sync.Once 中原子操作的使用是主要不受底層機器的記憶體模型的影響。 Go 的記憶體模型充當統一的抽象,確保不同硬體平台之間的行為一致,無論其特定的記憶體模型為何。

最佳化的快速路徑

要最佳化效能,請同步.Once 對於已設定完成標誌的常見場景採用快速路徑。此快速路徑利用atomic.LoadUint32 來檢查完成標誌而不取得互斥體。如果設定了該標誌,則函數立即傳回。

具有互斥鎖和原子儲存的慢速路徑

當快速路徑失敗時(即最初未設定完成),進入慢速路徑。取得互斥體以確保只有一個呼叫者可以繼續執行 f。 f完成後,使用atomic.StoreUint32設定done標誌,使其對其他goroutines可見。

並發讀取

即使設定了done標誌從原子角度來說,它並不保證並發讀取的安全。讀取受保護臨界區域以外的標誌需要使用atomic.LoadUint32。然而,由於互斥體提供了互斥,直接讀取臨界區是安全的。

綜上所述,Go 的sync.Once 利用atomic.StoreUint32 來確保done 標誌的修改一致且可見,無論底層記憶體 モデル 並避免資料競爭。原子操作和互斥體的結合提供了性能最佳化和正確性保證。

以上是為什麼 Go 的 `sync.Once` 使用 `atomic.StoreUint32` 而不是普通的賦值來設定 `done` 標誌?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板