亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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就能使用
  • 還內置了Store、Load、LoadOrStore、Delete、Range等操作方法,自行體驗。

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

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

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

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

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

  • 當且僅當?shù)谝淮卧L問某個變量時,進行初始化(寫);
  • 變量初始化過程中,所有讀都被阻塞,直到初始化完成;
  • 變量僅初始化一次,初始化完成后駐留在內存里。
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 通常用來保護臨界區(qū)和共享資源,條件變量 sync.Cond 用來協(xié)調想要訪問共享資源的 goroutine。

也就是在存在共享變量時,可以直接使用sync.Cond來協(xié)調共享變量,比如最常見的共享隊列,多消費多生產的模式。

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

創(chuàng)建實例

func NewCond(l Locker) *Cond

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

廣播喚醒所有

func (c *Cond) Broadcast()

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

喚醒一個協(xié)程

func (c *Cond) Signal()

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

等待

func (c *Cond) Wait()

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

舉個不恰當?shù)睦?,實現(xiàn)一個經典的生產者和消費者模式,但有先決條件:

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

生產者

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

消費者

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

關閉程序

func Shutdown() {
	cond.L.Lock()
	defer cond.L.Unlock()
	shuttingDown = true
	fmt.Println("要關閉咯,大家快消費")
	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, 隊列剩余 %d \n", cur, cnt)
		}
	}()
	time.Sleep(time.Second * 5)
	Shutdown()
	wg.Wait()
  • 分別創(chuàng)建生產者與消費者。
  • 生產10個,每5個休息1秒。
  • 持續(xù)消費。
  • 主程序關閉隊列。

輸出

生產咯,來消費吧
當前消費 1, 隊列剩余 0 
未關閉但空了,等待生產
生產咯,來消費吧
生產咯,來消費吧
當前消費 1, 隊列剩余 1 
當前消費 1, 隊列剩余 0 
未關閉但空了,等待生產
生產咯,來消費吧
生產咯,來消費吧
生產咯,來消費吧
當前消費 1, 隊列剩余 2 
當前消費 1, 隊列剩余 1 
當前消費 1, 隊列剩余 0 
未關閉但空了,等待生產
生產咯,來消費吧
生產咯,來消費吧
生產咯,來消費吧
生產咯,來消費吧
當前消費 1, 隊列剩余 1 
當前消費 1, 隊列剩余 2 
當前消費 1, 隊列剩余 1 
當前消費 1, 隊列剩余 0 
未關閉但空了,等待生產
要關閉咯,大家快消費
關閉咯,也消費完咯
當前消費 0, 隊列剩余 0

小結

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

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

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

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

相關文章

  • jenkins構建go及java項目的方法

    jenkins構建go及java項目的方法

    這篇文章主要介紹了jenkins構建go及java項目,本文通過圖文實例相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值了,需要的朋友可以參考下
    2021-04-04
  • 簡單聊聊Go語言的注釋

    簡單聊聊Go語言的注釋

    這篇文章主要介紹了簡單聊聊Go語言的注釋的相關資料,需要的朋友可以參考下
    2023-08-08
  • Golang錯誤處理:異常捕捉和恢復機制

    Golang錯誤處理:異常捕捉和恢復機制

    Golang中,異常處理是通過 defer + panic + recover 的方式來實現(xiàn)的,使用 defer 可以將清理操作注冊到函數(shù)執(zhí)行完畢后執(zhí)行,而 panic 和 recover 可以用于處理異常,通過組合使用這些功能,可以實現(xiàn)更加健壯的程序
    2024-01-01
  • 教你利用Golang可選參數(shù)實現(xiàn)可選模式

    教你利用Golang可選參數(shù)實現(xiàn)可選模式

    本文討論Golang函數(shù)可選參數(shù)及函數(shù)類型,以及如何利用可選函數(shù)類型實現(xiàn)可選模式。同時通過構造函數(shù)作為示例,實現(xiàn)強大帶可選參數(shù)的構造函數(shù),讓代碼更直觀、靈活、支持擴展
    2023-01-01
  • Go語言服務器開發(fā)之客戶端向服務器發(fā)送數(shù)據(jù)并接收返回數(shù)據(jù)的方法

    Go語言服務器開發(fā)之客戶端向服務器發(fā)送數(shù)據(jù)并接收返回數(shù)據(jù)的方法

    這篇文章主要介紹了Go語言服務器開發(fā)之客戶端向服務器發(fā)送數(shù)據(jù)并接收返回數(shù)據(jù)的方法,實例分析了客戶端的開發(fā)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • 基于go手動寫個轉發(fā)代理服務的代碼實現(xiàn)

    基于go手動寫個轉發(fā)代理服務的代碼實現(xiàn)

    這篇文章主要介紹了基于go手動寫個轉發(fā)代理服務的代碼實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-02-02
  • Go語言for-range函數(shù)使用技巧實例探究

    Go語言for-range函數(shù)使用技巧實例探究

    這篇文章主要為大家介紹了Go語言for-range函數(shù)使用技巧實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • 一文教你如何快速學會Go的切片和數(shù)組數(shù)據(jù)類型

    一文教你如何快速學會Go的切片和數(shù)組數(shù)據(jù)類型

    數(shù)組是屬于同一類型的元素的集合。切片是數(shù)組頂部的方便、靈活且功能強大的包裝器。本文就來和大家聊聊Go中切片和數(shù)組的使用,需要的可以參考一下
    2023-03-03
  • Golang中Error的設計與實踐詳解

    Golang中Error的設計與實踐詳解

    這篇文章主要為大家詳細介紹了Golang中Error的設計以及是具體如何處理錯誤的相關知識,文中的示例代碼簡潔易懂,需要的小伙伴可以跟隨小編一起學習一下
    2023-08-08
  • Go實現(xiàn)跨平臺的藍牙聊天室示例詳解

    Go實現(xiàn)跨平臺的藍牙聊天室示例詳解

    這篇文章主要為大家介紹了Go實現(xiàn)跨平臺的藍牙聊天室示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12

最新評論