欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go中sync.Once源碼的深度講解

 更新時間:2025年01月28日 09:53:08   作者:gopher_looklook  
sync.Once是Go語言標準庫中的一個同步原語,用于確保某個操作只執(zhí)行一次,本文將從源碼出發(fā)為大家詳細介紹一下sync.Once的具體使用,x希望對大家有所幫助

概念

sync.Once是Go語言標準庫中的一個同步原語,用于確保某個操作只執(zhí)行一次。它在多線程環(huán)境中非常有用,尤其是在需要初始化共享資源或執(zhí)行某些一次性任務時。

簡單示例

當我們在web服務訪問某個路由時,如果需要事先獲取某些配置,往往會寫一個loadConfig函數(shù),獲取一個cfg配置項。多次路由訪問所需要獲取的配置項通常是相同的,如果對于每次路由訪問,都加載一次loadConfig函數(shù),會導致產(chǎn)生一些不必要的開銷。如果loadConfig涉及到讀取文件、解析配置、網(wǎng)絡請求時,有可能會額外增加的請求響應時間,降低服務的吞吐量。使用sync.Once包提供的Do函數(shù),就可以只在第一次請求時調(diào)用loadConfig函數(shù)加載配置,之后的請求都復用第一次請求的配置,縮短響應時間。

package main

import (
    "log"
    "net/http"
    "sync"
)

type Config struct {
    APIKey   string
    LogLevel string
}

var (
    config *Config
    once   sync.Once
)

func loadConfig() {
    // 模擬從文件或環(huán)境變量加載配置
    config = &Config{
       APIKey:   "secret-key",
       LogLevel: "debug",
    }
    log.Println("Configuration loaded")
}

func GetConfig() *Config {
    once.Do(loadConfig) // 僅第一次訪問時會執(zhí)行l(wèi)oadConfig函數(shù)
    return config
}

func handler(w http.ResponseWriter, r *http.Request) {
    cfg := GetConfig()
    log.Printf("Request handled with API key: %s", cfg.APIKey)
    w.Write([]byte("OK"))
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8888", nil))
}

源碼解讀

源碼文件:src/sync/once.go (go 1.23 版本)

package sync

import (
    "sync/atomic"
)

type Once struct {
    done atomic.Uint32 // 是否已執(zhí)行標識位,0-未執(zhí)行 1-已執(zhí)行
    m    Mutex         // 互斥鎖,確保并發(fā)安全
}

func (o *Once) Do(f func()) {
    // 第一次執(zhí)行Do函數(shù)時,原子操作檢查o.done==0,執(zhí)行doSlow函數(shù)后,o.done==1
    // 第二次及之后執(zhí)行Do函數(shù),原子操作檢查o.done標識位為1,Do函數(shù)不執(zhí)行任何功能,確保了f函數(shù)只在第一次被執(zhí)行
    if o.done.Load() == 0 {
       o.doSlow(f) // 調(diào)用doSlow函數(shù)執(zhí)行f方法。第一次執(zhí)行時,同一時間可能有多個goroutine嘗試同時執(zhí)行doSlow函數(shù)
    }
}

func (o *Once) doSlow(f func()) {
    o.m.Lock() // 加鎖保護,避免多個goroutine同時繞過之前的原子操作檢查,并發(fā)修改o.done的值
    defer o.m.Unlock()
    // 二次檢查o.done的值,同一時間并發(fā)執(zhí)行doSlow函數(shù)的goroutine,在第一個goroutine將o.done置為1并解除互斥鎖后,
    // 剩下的goroutine識別到自身的o.done已經(jīng)被設為1,無法繞過二次檢查
    if o.done.Load() == 0 { 
       defer o.done.Store(1) // 需要在f()函數(shù)執(zhí)行完成之后,原子性地將o.done設為1
       f() // 執(zhí)行f方法,一定只有一個goroutine會調(diào)用這個方法
    }
}

可以看到,once.go文件的代碼非常精煉。僅定義了一個含2個非導出字段donem的結構體Once,并提供了一個doSlow方法用于執(zhí)行f函數(shù)。當我們調(diào)用Do方法時,程序經(jīng)歷了幾個關鍵步驟:

  • 判斷done標志位是否等于0,如果是,說明f函數(shù)還沒有被執(zhí)行,執(zhí)行doSlow方法
  • mu互斥鎖加鎖,防止多個goroutine并發(fā)操作
  • double-check done標志位是否等于0,如果是,說明f函數(shù)還沒有被執(zhí)行,執(zhí)行f函數(shù)
  • f函數(shù)執(zhí)行完成之后,再將done標志位原子性設為1。使用原子操作是從內(nèi)存可見性的角度出發(fā),如果done使用uint32而不是atomic.Uint32,done修改可能不會立即被其它goroutine感知,解鎖后仍有可能存在goroutinedone等于0,重復執(zhí)行f函數(shù)
  • mu互斥鎖解鎖。此時進入到doSlow函數(shù)的其它goroutine也感知到了o.done等于1,不會重復執(zhí)行f函數(shù)了

總結

上文就是針對Go源碼sync.Once原理和使用方式的講解。在實際開發(fā)中,sync.Once的使用還是非常普遍的。掌握sync.Once的底層原理,有助于我們在今后的開發(fā)中更有把握地利用它永遠只執(zhí)行一次函數(shù)的特性,完成復雜的技術需求或者業(yè)務需求。

到此這篇關于Go中sync.Once源碼的深度講解的文章就介紹到這了,更多相關Go sync.Once內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • golang gorm 結構體的表字段缺省值設置方式

    golang gorm 結構體的表字段缺省值設置方式

    這篇文章主要介紹了golang gorm 結構體的表字段缺省值設置方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go 中閉包的底層原理

    Go 中閉包的底層原理

    這篇文章主要介紹了Go 中閉包的底層原理,閉包的基本原理是一種現(xiàn)象,一個函數(shù)內(nèi)引用了外部的局部變量的現(xiàn)象,帶著些許的了解和小編一起進入文章正題學習
    2021-10-10
  • GO語言基本類型分析

    GO語言基本類型分析

    這篇文章主要介紹了GO語言基本類型,較為詳細的分析了整形、浮點型、字符串、指針等類型的具體用法,是深入學習GO語言所必須掌握的重要基礎,需要的朋友可以參考下
    2014-12-12
  • Go語言中map使用和并發(fā)安全詳解

    Go語言中map使用和并發(fā)安全詳解

    golang?自帶的map不是并發(fā)安全的,并發(fā)讀寫會報錯,所以下面這篇文章主要給大家介紹了關于Go語言中map使用和并發(fā)安全的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • Golang字符串拼接的性能以及原理詳解

    Golang字符串拼接的性能以及原理詳解

    最近在做性能優(yōu)化,有個函數(shù)里面的耗時特別長,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在golang里面其實有很多種實現(xiàn),下面這篇文章主要給大家介紹了關于Golang字符串拼接的性能以及原理的相關資料,需要的朋友可以參考下
    2023-06-06
  • Golang讀寫二進制文件方法總結

    Golang讀寫二進制文件方法總結

    使用?Golang?的?encoding/gob?包讀寫二進制文件非常方便,而且代碼量也非常少,本文就來通過兩個示例帶大家了解一下encoding/gob的具體用法吧
    2023-05-05
  • Go設計模式之訪問者模式講解和代碼示例

    Go設計模式之訪問者模式講解和代碼示例

    訪問者是一種行為設計模式, 允許你在不修改已有代碼的情況下向已有類層次結構中增加新的行為,本文將通過代碼示例給大家詳細的介紹一下Go設計模式之訪問者模式,需要的朋友可以參考下
    2023-08-08
  • goland服務熱重啟的配置文件

    goland服務熱重啟的配置文件

    這篇文章主要介紹了goland服務熱重啟的配置文件,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • go語言-在mac下brew升級golang

    go語言-在mac下brew升級golang

    這篇文章主要介紹了go語言-在mac下brew升級golang,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 詳解玩轉(zhuǎn)直播系列之消息模塊演進

    詳解玩轉(zhuǎn)直播系列之消息模塊演進

    本篇文章針對秀場直播,簡單地描述一下消息模型,說明一下我們消息模型的架構,并結合我們一年以來,通過處理不同的業(yè)務線上問題,來進行演進式的消息模型架構的升級與調(diào)整,將此整理成文,并分享給大家
    2021-06-06

最新評論