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

GO語言并發(fā)之好用的sync包詳解

 更新時間:2022年12月29日 09:19:33   作者:機(jī)智的程序員小熊  
標(biāo)準(zhǔn)庫中的sync包在我們的日常開發(fā)中用的頗為廣泛,那么大家對sync包的用法知道多少呢,這篇文章就大致講一下sync包和它的使用,感興趣的可以學(xué)習(xí)一下

sync.Map 并發(fā)安全的Map

反例如下,兩個Goroutine分別讀寫。

func unsafeMap(){
	var wg sync.WaitGroup
	m := make(map[int]int)
	wg.Add(2)
	go func() {
		defer wg.Done()
		for i := 0; i < 10000; i++ {
			m[i] = i
		}
	}()

	go func() {
		defer wg.Done()
		for i := 0; i < 10000; i++ {
			fmt.Println(m[i])
		}
	}()
	wg.Wait()
}

執(zhí)行報錯:

0
fatal error: concurrent map read and map write

goroutine 7 [running]:
runtime.throw({0x10a76fa, 0x0})
......

使用并發(fā)安全的Map

func safeMap() {
	var wg sync.WaitGroup
	var m sync.Map
	wg.Add(2)
	go func() {
		defer wg.Done()
		for i := 0; i < 10000; i++ {
			m.Store(i, i)
		}
	}()

	go func() {
		defer wg.Done()
		for i := 0; i < 10000; i++ {
			fmt.Println(m.Load(i))
		}
	}()
	wg.Wait()
}
  • 不需要make就能使用
  • 還內(nèi)置了StoreLoad、LoadOrStoreDelete、Range等操作方法,自行體驗(yàn)。

sync.Once 只執(zhí)行一次

很多場景下我們需要確保某些操作在高并發(fā)的場景下只執(zhí)行一次,例如只加載一次配置文件、只關(guān)閉一次通道等。

init 函數(shù)是當(dāng)所在的 package 首次被加載時執(zhí)行,若遲遲未被使用,則既浪費(fèi)了內(nèi)存,又延長了程序加載時間。

sync.Once 可以在代碼的任意位置初始化和調(diào)用,因此可以延遲到使用時再執(zhí)行,并發(fā)場景下是線程安全的。

在多數(shù)情況下,sync.Once 被用于控制變量的初始化,這個變量的讀寫滿足如下三個條件:

  • 當(dāng)且僅當(dāng)?shù)谝淮卧L問某個變量時,進(jìn)行初始化(寫);
  • 變量初始化過程中,所有讀都被阻塞,直到初始化完成;
  • 變量僅初始化一次,初始化完成后駐留在內(nèi)存里。
var loadOnce sync.Once
var x int
for i:=0;i<10;i++{
    loadOnce.Do(func() {
        x++
    })
}
fmt.Println(x)

輸出

1

sync.Cond 條件變量控制

sync.Cond 基于互斥鎖/讀寫鎖,它和互斥鎖的區(qū)別是什么呢?

互斥鎖 sync.Mutex 通常用來保護(hù)臨界區(qū)和共享資源,條件變量 sync.Cond 用來協(xié)調(diào)想要訪問共享資源的 goroutine。

也就是在存在共享變量時,可以直接使用sync.Cond來協(xié)調(diào)共享變量,比如最常見的共享隊(duì)列,多消費(fèi)多生產(chǎn)的模式。

我一開始也很疑惑為什么不使用channelselect的模式來做生產(chǎn)者消費(fèi)者模型(實(shí)際上也可以),這一節(jié)不是重點(diǎn)就不展開討論了。

創(chuàng)建實(shí)例

func NewCond(l Locker) *Cond

NewCond 創(chuàng)建 Cond 實(shí)例時,需要關(guān)聯(lián)一個鎖。

廣播喚醒所有

func (c *Cond) Broadcast()

Broadcast 喚醒所有等待條件變量 cgoroutine,無需鎖保護(hù)。

喚醒一個協(xié)程

func (c *Cond) Signal()

Signal 只喚醒任意 1 個等待條件變量 cgoroutine,無需鎖保護(hù)。

等待

func (c *Cond) Wait()

每個 Cond 實(shí)例都會關(guān)聯(lián)一個鎖 L(互斥鎖 *Mutex,或讀寫鎖 *RWMutex),當(dāng)修改條件或者調(diào)用 Wait 方法時,必須加鎖。

舉個不恰當(dāng)?shù)睦樱瑢?shí)現(xiàn)一個經(jīng)典的生產(chǎn)者和消費(fèi)者模式,但有先決條件:

  • 邊生產(chǎn)邊消費(fèi),可以多生產(chǎn)多消費(fèi)。
  • 生產(chǎn)后通知消費(fèi)。
  • 隊(duì)列為空時,暫停等待。
  • 支持關(guān)閉,關(guān)閉后等待消費(fèi)結(jié)束。
  • 關(guān)閉后依然可以生產(chǎn),但無法消費(fèi)了。
var (
	cnt          int
	shuttingDown = false
	cond         = sync.NewCond(&sync.Mutex{})
)
  • cnt 為隊(duì)列,這里直接用變量代替了,變量就是隊(duì)列長度。
  • shuttingDown 消費(fèi)關(guān)閉狀態(tài)。
  • cond 現(xiàn)成的隊(duì)列控制。

生產(chǎn)者

func Add(entry int) {
	cond.L.Lock()
	defer cond.L.Unlock()
	cnt += entry
	fmt.Println("生產(chǎn)咯,來消費(fèi)吧")
	cond.Signal()
}

消費(fèi)者

func Get() (int, bool) {
	cond.L.Lock()
	defer cond.L.Unlock()
	for cnt == 0 && !shuttingDown {
		fmt.Println("未關(guān)閉但空了,等待生產(chǎn)")
		cond.Wait()
	}
	if cnt == 0 {
		fmt.Println("關(guān)閉咯,也消費(fèi)完咯")
		return 0, true
	}
	cnt--
	return 1, false
}

關(guān)閉程序

func Shutdown() {
	cond.L.Lock()
	defer cond.L.Unlock()
	shuttingDown = true
	fmt.Println("要關(guān)閉咯,大家快消費(fèi)")
	cond.Broadcast()
}

主程序

var wg sync.WaitGroup
	wg.Add(2)
	time.Sleep(time.Second)
	go func() {
		defer wg.Done()
		for i := 0; i < 10; i++ {
			go Add(1)
			if i%5 == 0 {
				time.Sleep(time.Second)
			}
		}
	}()
	go func() {
		defer wg.Done()
		shuttingDown := false
		for !shuttingDown {
			var cur int
			cur, shuttingDown = Get()
			fmt.Printf("當(dāng)前消費(fèi) %d, 隊(duì)列剩余 %d \n", cur, cnt)
		}
	}()
	time.Sleep(time.Second * 5)
	Shutdown()
	wg.Wait()
  • 分別創(chuàng)建生產(chǎn)者與消費(fèi)者。
  • 生產(chǎn)10個,每5個休息1秒。
  • 持續(xù)消費(fèi)。
  • 主程序關(guān)閉隊(duì)列。

輸出

生產(chǎn)咯,來消費(fèi)吧
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 0 
未關(guān)閉但空了,等待生產(chǎn)
生產(chǎn)咯,來消費(fèi)吧
生產(chǎn)咯,來消費(fèi)吧
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 1 
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 0 
未關(guān)閉但空了,等待生產(chǎn)
生產(chǎn)咯,來消費(fèi)吧
生產(chǎn)咯,來消費(fèi)吧
生產(chǎn)咯,來消費(fèi)吧
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 2 
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 1 
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 0 
未關(guān)閉但空了,等待生產(chǎn)
生產(chǎn)咯,來消費(fèi)吧
生產(chǎn)咯,來消費(fèi)吧
生產(chǎn)咯,來消費(fèi)吧
生產(chǎn)咯,來消費(fèi)吧
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 1 
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 2 
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 1 
當(dāng)前消費(fèi) 1, 隊(duì)列剩余 0 
未關(guān)閉但空了,等待生產(chǎn)
要關(guān)閉咯,大家快消費(fèi)
關(guān)閉咯,也消費(fèi)完咯
當(dāng)前消費(fèi) 0, 隊(duì)列剩余 0

小結(jié)

1.sync.Map 并發(fā)安全的Map。

2.sync.Once 只執(zhí)行一次,適用于配置讀取、通道關(guān)閉。

3.sync.Cond 控制協(xié)調(diào)共享資源。

以上就是GO語言并發(fā)之好用的sync包詳解的詳細(xì)內(nèi)容,更多關(guān)于GO語言 sync包的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • golang如何操作csv文件詳解

    golang如何操作csv文件詳解

    這篇文章主要給大家介紹了關(guān)于golang如何操作csv文件的相關(guān)資料,以及使用Golang導(dǎo)出CSV數(shù)據(jù)并解決數(shù)據(jù)亂碼問題的解決辦法,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-02-02
  • Golang收支記賬程序詳細(xì)編寫過程

    Golang收支記賬程序詳細(xì)編寫過程

    這篇文章主要介紹了Golang實(shí)現(xiàn)收支記賬程序流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • 使用systemd部署和守護(hù)golang應(yīng)用程序的操作方法

    使用systemd部署和守護(hù)golang應(yīng)用程序的操作方法

    systemd是一個流行的守護(hù)進(jìn)程管理器,可以輕松管理服務(wù)的啟動、停止、重啟等操作,讓我們的應(yīng)用程序始終保持在線,本文介紹了如何使用systemd部署和守護(hù)golang應(yīng)用程序,感興趣的朋友一起看看吧
    2023-10-10
  • 深入解析golang中的標(biāo)準(zhǔn)庫flag

    深入解析golang中的標(biāo)準(zhǔn)庫flag

    Go語言內(nèi)置的flag包實(shí)現(xiàn)了命令行參數(shù)的解析,flag包使得開發(fā)命令行工具更為簡單,下面通過本文給大家詳細(xì)介紹下golang中的標(biāo)準(zhǔn)庫flag相關(guān)知識,感興趣的朋友一起看看吧
    2021-11-11
  • go語言中嵌套結(jié)構(gòu)體的實(shí)現(xiàn)

    go語言中嵌套結(jié)構(gòu)體的實(shí)現(xiàn)

    在Go語言中,嵌套結(jié)構(gòu)體可定義為一個結(jié)構(gòu)體內(nèi)包含另一個結(jié)構(gòu)體,嵌套可以是值嵌套或指針嵌套,兩者在內(nèi)存分配和修改影響上有顯著區(qū)別,本文就來詳細(xì)的介紹一下,感興趣的可以了解一下
    2024-09-09
  • Golang使用zlib壓縮和解壓縮字符串

    Golang使用zlib壓縮和解壓縮字符串

    本文給大家分享的是Golang使用zlib壓縮和解壓縮字符串的方法和示例,有需要的小伙伴可以參考下
    2017-02-02
  • Golang中omitempty關(guān)鍵字的具體實(shí)現(xiàn)

    Golang中omitempty關(guān)鍵字的具體實(shí)現(xiàn)

    本文主要介紹了Golang中omitempty關(guān)鍵字的具體實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • GoFrame?gtree樹形結(jié)構(gòu)的使用技巧示例

    GoFrame?gtree樹形結(jié)構(gòu)的使用技巧示例

    這篇文章主要為大家介紹了GoFrame?gtree樹形結(jié)構(gòu)的使用技巧示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Goland字符串格式化樣式中“\r“的作用詳解

    Goland字符串格式化樣式中“\r“的作用詳解

    這篇文章主要介紹了Goland字符串格式化樣式中“\r“的作用,"\r"起的作用是回到行首,當(dāng)前控制臺輸出,輸出完以后回到當(dāng)前行的行首,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • 解決 Golang VS Code 插件下載安裝失敗的問題

    解決 Golang VS Code 插件下載安裝失敗的問題

    這篇文章主要介紹了解決 Golang VS Code 插件下載安裝失敗,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05

最新評論

阿瓦提县| 云林县| 岫岩| 忻州市| 白山市| 丽江市| 绵阳市| 和龙市| 冷水江市| 临西县| 琼结县| 阿克| 天祝| 汕头市| 东港市| 确山县| 莱阳市| 柏乡县| 宜兰县| 大悟县| 油尖旺区| 林周县| 含山县| 东山县| 宁远县| 和田县| 玉山县| 清水县| 原平市| 吉木萨尔县| 新乐市| 会昌县| 宽甸| 日照市| 重庆市| 娱乐| 怀柔区| 伊宁县| 汶川县| 湟源县| 化州市|