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

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

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

概念

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

簡(jiǎn)單示例

當(dāng)我們?cè)趙eb服務(wù)訪問某個(gè)路由時(shí),如果需要事先獲取某些配置,往往會(huì)寫一個(gè)loadConfig函數(shù),獲取一個(gè)cfg配置項(xiàng)。多次路由訪問所需要獲取的配置項(xiàng)通常是相同的,如果對(duì)于每次路由訪問,都加載一次loadConfig函數(shù),會(huì)導(dǎo)致產(chǎn)生一些不必要的開銷。如果loadConfig涉及到讀取文件、解析配置、網(wǎng)絡(luò)請(qǐng)求時(shí),有可能會(huì)額外增加的請(qǐng)求響應(yīng)時(shí)間,降低服務(wù)的吞吐量。使用sync.Once包提供的Do函數(shù),就可以只在第一次請(qǐng)求時(shí)調(diào)用loadConfig函數(shù)加載配置,之后的請(qǐng)求都復(fù)用第一次請(qǐng)求的配置,縮短響應(yīng)時(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) // 僅第一次訪問時(shí)會(huì)執(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í)行標(biāo)識(shí)位,0-未執(zhí)行 1-已執(zhí)行
    m    Mutex         // 互斥鎖,確保并發(fā)安全
}

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

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

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

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

總結(jié)

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

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

相關(guān)文章

  • 一文帶你熟悉Go語言中的for循環(huán)

    一文帶你熟悉Go語言中的for循環(huán)

    這篇文章主要和大家分享一下Go語言中for循環(huán)的定義與使用,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2022-11-11
  • golang1.21新特性全面講解

    golang1.21新特性全面講解

    經(jīng)過了半年左右的開發(fā),golang?1.21?最近正式發(fā)布了,這個(gè)版本中有不少重要的新特性和變更,尤其是在泛型相關(guān)的代碼上,下面小編就來和大家好好嘮嘮吧
    2023-08-08
  • 詳解golang中的method

    詳解golang中的method

    這篇文章主要介紹了golang中的method的相關(guān)資料,幫助大家更好的理解和使用golang,感興趣的朋友可以了解下
    2021-01-01
  • Golang必知必會(huì)之Go?Mod命令詳解

    Golang必知必會(huì)之Go?Mod命令詳解

    go mod可以使項(xiàng)目從GOPATH的強(qiáng)制依賴中獨(dú)立出來,也就是說你的項(xiàng)目依賴不再需要放在在GOPATH下面了,下面這篇文章主要給大家介紹了關(guān)于Golang必知必會(huì)之Go?Mod命令的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • 詳解golang碎片整理之 fmt.Scan

    詳解golang碎片整理之 fmt.Scan

    本文介紹了從golang語言中fmt包從標(biāo)準(zhǔn)輸入獲取數(shù)據(jù)的Scan系列函數(shù)、從io.Reader中獲取數(shù)據(jù)的Fscan系列函數(shù)以及從字符串中獲取數(shù)據(jù)的Sscan系列函數(shù)的用法,感興趣的小伙伴們可以參考一下
    2019-05-05
  • go語言中GoMock安裝使用詳解

    go語言中GoMock安裝使用詳解

    這篇文章主要為大家介紹了go語言中GoMock安裝使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Golang中Slice 底層機(jī)制的實(shí)現(xiàn)

    Golang中Slice 底層機(jī)制的實(shí)現(xiàn)

    本文主要介紹了Golang中Slice 底層機(jī)制的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-03-03
  • Go搭建高效的Gin Web目錄結(jié)構(gòu)

    Go搭建高效的Gin Web目錄結(jié)構(gòu)

    本文主要介紹了Go搭建高效的Gin Web目錄結(jié)構(gòu),構(gòu)建一個(gè)既高效又便于管理的項(xiàng)目架構(gòu),助力開發(fā)者打造既快速響應(yīng)又易于維護(hù)的Web應(yīng)用程序,感興趣的可以了解一下
    2025-08-08
  • Go基礎(chǔ)教程之環(huán)境搭建及常用命令

    Go基礎(chǔ)教程之環(huán)境搭建及常用命令

    這篇文章主要介紹了Go基礎(chǔ)教程之環(huán)境搭建及常用命令的相關(guān)資料,包括Go語言簡(jiǎn)介、環(huán)境配置、包管理工具GoModules以及常用命令的全面介紹,需要的朋友可以參考下
    2025-03-03
  • 詳解Go語言如何使用標(biāo)準(zhǔn)庫(kù)sort對(duì)切片進(jìn)行排序

    詳解Go語言如何使用標(biāo)準(zhǔn)庫(kù)sort對(duì)切片進(jìn)行排序

    Sort?標(biāo)準(zhǔn)庫(kù)提供了對(duì)基本數(shù)據(jù)類型的切片和自定義類型的切片進(jìn)行排序的函數(shù)。今天主要分享的內(nèi)容是使用?Go?標(biāo)準(zhǔn)庫(kù)?sort?對(duì)切片進(jìn)行排序,感興趣的可以了解一下
    2022-12-12

最新評(píng)論

宁国市| 丽水市| 聊城市| 乳山市| 蚌埠市| 酒泉市| 来凤县| 靖江市| 安乡县| 南丰县| 措勤县| 陵川县| 闽侯县| 赤壁市| 原平市| 巢湖市| 衡阳县| 临高县| 凌源市| 青阳县| 汨罗市| 桑日县| 高台县| 内江市| 丹寨县| 昭通市| 凯里市| 黔西县| 南江县| 海南省| 沙河市| 嘉义市| 苍溪县| 登封市| 惠来县| 报价| 陇川县| 商南县| 绵阳市| 宜川县| 凭祥市|