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

GoLang并發(fā)編程中條件變量sync.Cond的使用

 更新時間:2023年01月10日 08:31:57   作者:鯤鵬飛九萬里  
Go標準庫提供Cond原語的目的是,為等待/通知場景下的并發(fā)問題提供支持,本文主要介紹了Go并發(fā)編程sync.Cond的具體使用,具有一定的參考價值,感興趣的可以了解一下

一、條件變量與互斥鎖

  • 條件變量是基于互斥鎖的,它必須基于互斥鎖才能發(fā)揮作用;
  • 條件變量并不是用來保護臨界區(qū)和共享資源的,它是用來協(xié)調(diào)想要訪問共享資源的那些線程的;
  • 在Go語言中,條件變量最大的優(yōu)勢是效率方面的提升。當共享資源不滿足條件的時候,想操作它的線程不用循環(huán)往返地檢查了,只要等待通知就好了。

二、條件變量與互斥鎖的配合使用

條件變量的初始化離不開互斥鎖,并且它的方法有點也是基于互斥鎖的。

條件變量提供的三個方法:等待通知(wait)、單發(fā)通知(signal)、廣發(fā)通知(broadcast)。

三、條件變量的使用

創(chuàng)建鎖和條件

	// mailbox 代表信箱
	// 0 代表信箱是空的,1代表信箱是滿的
	var mailbox uint8
	// lock 代表信箱上的鎖
	var lock sync.RWMutex
	// sendCond 代表專用于發(fā)信的條件變量
	var sendCond = sync.NewCond(&lock)
	// reveCond 代表專用于收信的條件變量
	var reveCond = sync.NewCond(lock.RLocker())
  • sync.Cond類型并不是開箱即用的,只能利用sync.NewCond創(chuàng)建它的指針值。這個函數(shù)需要sync.Locker類型的參數(shù)值。
  • sync.Locker是一個接口,它包含兩個指針方法,即Lock()Unlock();因此,sync.Mutexsync.RWMutex這兩個類型的指針類型才是sync.Locker接口的實現(xiàn)類型。
  • 上面lock變量的Lock方法和Unlock方法分別用于對其中寫鎖的鎖定和解鎖,它們與sendCond變量的含義對應。
  • lock.RLocker()得到的值,擁有Lock和Unlock方法,其內(nèi)部會分別調(diào)用lock變量的RLock方法和RUnlock方法;

使用

lock.Lock()
for mailbox == 1 {
 sendCond.Wait()
}
mailbox = 1
lock.Unlock()
recvCond.Signal()
lock.RLock()
for mailbox == 0 {
 recvCond.Wait()
}
mailbox = 0
lock.RUnlock()
sendCond.Signal()

完整代碼:

package main
import (
	"log"
	"sync"
	"time"
)
func main() {
	// mailbox 代表信箱
	// 0 代表信箱是空的,1代表信箱是滿的
	var mailbox uint8
	// lock 代表信箱上的鎖
	var lock sync.RWMutex
	// sendCond 代表專用于發(fā)信的條件變量
	var sendCond = sync.NewCond(&lock)
	// reveCond 代表專用于收信的條件變量
	var reveCond = sync.NewCond(lock.RLocker())
	// sign 用于傳遞演示完成的信號
	sign := make(chan struct{}, 2)
	max := 5
	go func(max int) { // 用于發(fā)信
		defer func() {
			sign <- struct{}{}
		}()
		for i := 1; i <= max; i++ {
			time.Sleep(time.Millisecond * 5)
			lock.Lock()
			for mailbox == 1 {
				sendCond.Wait()
			}
			log.Printf("sender [%d]: the mailbox is empty.", i)
			mailbox = 1
			log.Printf("sender [%d]: the letter has been sent.", i)
			lock.Unlock()
			reveCond.Signal()
		}
	}(max)
	go func(max int) { // 用于收信
		defer func() {
			sign <- struct{}{}
		}()
		for j := 1; j <= max; j++ {
			time.Sleep(time.Millisecond * 500)
			lock.RLock()
			for mailbox == 0 {
				reveCond.Wait()
			}
			log.Printf("receiver [%d]: the mailbox is full.", j)
			mailbox = 0
			log.Printf("receiver [%d]: the letter has been received.", j)
			lock.RUnlock()
			sendCond.Signal()
		}
	}(max)
	<-sign
	<-sign
}

四、條件變量的Wait方法做了什么

(1)條件變量Wait方法主要做的四件事

條件變量的Wait方法主要做了四件事:

  • 把調(diào)用它的goroutine(也就是當前goroutine)加入到當前條件變量的通知隊列中;
  • 解鎖當前條件變量基于的那個互斥鎖;
  • 讓當前的goroutine處于等待狀態(tài),等到通知到來時再決定是否喚醒它。此時,這個goroutine就會阻塞在調(diào)用這個Wait方法的那行代碼上;
  • 如果通知到來并決定喚醒這個goroutine,那么就在喚醒它之后重新鎖定當前條件變量基于的互斥鎖。自此以后,當前的goroutine就會繼續(xù)執(zhí)行后面的代碼了。

(2)為什么要先要鎖定條件變量基于的互斥鎖,才能調(diào)用它的wait方法

因為條件變量的wait方法在阻塞當前的goroutine之前,會解鎖它基于的互斥鎖。所以在調(diào)用wait方法之前,必須先鎖定這個互斥鎖,否則在調(diào)用這個wait方法時,就會引發(fā)一個不可恢復的panic。

如果條件變量的Wait方法不先解鎖互斥鎖的話,那就會造成兩個后果:不是當前的程序因panic而崩潰,就是相關的goroutine全面阻塞。

(3)為什么用for語句來包裹調(diào)用的wait方法表達式,用if語句不行嗎

if語句只會對共享資源的狀態(tài)檢查一次,而for語句卻可以做多次檢查,直到這個狀態(tài)改變?yōu)橹埂?/p>

之所以做多次檢查,主要是為了保險起見。如果一個goroutine因收到通知而被喚醒,但卻發(fā)現(xiàn)共享資源的狀態(tài),依然不符合它的要求i,那么就應該再次調(diào)用條件變量的Wait方法,并繼續(xù)等待下次通知的到來。

這種情況是很有可能發(fā)生的,具體如下面所示:

  • 有多個 goroutine 在等待共享資源的同一種狀態(tài)。比如,它們都在等mailbox變量的值不為0的時候再把它的值變?yōu)?,這就相當于有多個人在等著我向信箱里放置情報。雖然等待的 goroutine 有多個,但每次成功的 goroutine 卻只可能有一個。別忘了,條件變量的Wait方法會在當前的 goroutine 醒來后先重新鎖定那個互斥鎖。在成功的 goroutine 最終解鎖互斥鎖之后,其他的 goroutine 會先后進入臨界區(qū),但它們會發(fā)現(xiàn)共享資源的狀態(tài)依然不是它們想要的。這個時候,for循環(huán)就很有必要了。
  • 共享資源可能有的狀態(tài)不是兩個,而是更多。比如,mailbox變量的可能值不只有0和1,還有2、3、4。這種情況下,由于狀態(tài)在每次改變后的結(jié)果只可能有一個,所以,在設計合理的前提下,單一的結(jié)果一定不可能滿足所有 goroutine 的條件。那些未被滿足的 goroutine 顯然還需要繼續(xù)等待和檢查。
  • 有一種可能,共享資源的狀態(tài)只有兩個,并且每種狀態(tài)都只有一個 goroutine 在關注,就像我們在主問題當中實現(xiàn)的那個例子那樣。不過,即使是這樣,使用for語句仍然是有必要的。原因是,在一些多 CPU 核心的計算機系統(tǒng)中,即使沒有收到條件變量的通知,調(diào)用其Wait方法的 goroutine 也是有可能被喚醒的。這是由計算機硬件層面決定的,即使是操作系統(tǒng)(比如 Linux)本身提供的條件變量也會如此。

綜上所述,在包裹條件變量的Wait方法的時候,我們總是應該使用for語句。

不要用if語句,因為它不能重復地執(zhí)行“檢查狀態(tài) - 等待通知 - 被喚醒”的這個流程。

(4)條件變量的Signal方法和Broadcast方法

條件變量signal方法和Broadcast方法都是用來發(fā)送通知的,不同的是,前者的通知只會喚醒一個因此而等待的goroutine,而后者的通知卻會喚醒所有為此等待的goroutine。

條件變量的Wait方法總會把當前的 goroutine 添加到通知隊列的隊尾,而它的Signal方法總會從通知隊列的隊首開始,查找可被喚醒的 goroutine。所以,因Signal方法的通知,而被喚醒的 goroutine 一般都是最早等待的那一個。

條件變量Signal方法和Broadcast方法放置的位置:

與Wait方法不同,條件變量的Signal方法和Broadcast方法并不需要在互斥鎖的保護下執(zhí)行。恰恰相反,我們最好在解鎖條件變量基于的那個互斥鎖之后,再去調(diào)用它的這兩個方法。這更有利于程序的運行效率。

條件變量的通知具有即時性:

如果發(fā)送通知的時候沒有 goroutine 為此等待,那么該通知就會被直接丟棄。在這之后才開始等待的 goroutine 只可能被后面的通知喚醒。

到此這篇關于GoLang并發(fā)編程中條件變量sync.Cond的使用的文章就介紹到這了,更多相關Go sync.Cond內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • GO中sync包自由控制并發(fā)示例詳解

    GO中sync包自由控制并發(fā)示例詳解

    這篇文章主要為大家介紹了GO中sync包自由控制并發(fā)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • go mod 依賴管理的具體使用

    go mod 依賴管理的具體使用

    在Go語言開發(fā)中,依賴管理是一項非常重要的工作,Go mod作為官方的包管理工具已經(jīng)成為了Go語言依賴管理的首選方式,本文就來介紹一下go mod 依賴管理的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Go1.21新增slices包中函數(shù)的用法詳解

    Go1.21新增slices包中函數(shù)的用法詳解

    Go?1.21新增的?slices?包提供了很多和切片相關的函數(shù),可以用于任何類型的切片,本文為大家整理了部分函數(shù)的具體用法,感興趣的小伙伴可以了解一下
    2023-08-08
  • 初識Golang?Mutex互斥鎖的使用

    初識Golang?Mutex互斥鎖的使用

    在學習操作系統(tǒng)的時候,我們應該都學習過臨界區(qū)、互斥鎖這些概念,用于在并發(fā)環(huán)境下保證狀態(tài)的正確性。在?Go語言?里面互斥鎖是?sync.Mutex?,我們本篇文章就來學習下為什么要使用互斥鎖、如何使用互斥鎖,以及使用時的常見問題
    2022-10-10
  • PHP和GO對接ChatGPT實現(xiàn)聊天機器人效果實例

    PHP和GO對接ChatGPT實現(xiàn)聊天機器人效果實例

    這篇文章主要為大家介紹了PHP和GO對接ChatGPT實現(xiàn)聊天機器人效果實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • 基于原生Go語言開發(fā)一個博客系統(tǒng)

    基于原生Go語言開發(fā)一個博客系統(tǒng)

    這篇文章主要為大家詳細介紹了如何基于原生Go語言開發(fā)一個簡單的博客系統(tǒng),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-02-02
  • 一文帶你了解Go語言中方法的調(diào)用

    一文帶你了解Go語言中方法的調(diào)用

    這篇文章主要和大家分享一下Go語言中的方法的調(diào)用,文中的示例代碼講解詳細,對我們學習Go語言有一定的幫助,需要的小伙伴可以參考一下
    2022-12-12
  • Golang?WorkerPool線程池并發(fā)模式示例詳解

    Golang?WorkerPool線程池并發(fā)模式示例詳解

    這篇文章主要為大家介紹了Golang?WorkerPool線程池并發(fā)模式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • go本地環(huán)境配置及vscode go插件安裝的詳細教程

    go本地環(huán)境配置及vscode go插件安裝的詳細教程

    這篇文章主要介紹了go本地環(huán)境配置及vscode go插件安裝的詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • 深入了解Golang?哈希算法之MD5、SHA-1和SHA-256

    深入了解Golang?哈希算法之MD5、SHA-1和SHA-256

    哈希算法是計算機科學領域中一種重要的技術,它將任意長度的輸入數(shù)據(jù)映射為固定長度的哈希值,在本篇文章中,我們將深入探討Golang中的哈希算法,從多個方面介紹其詳細內(nèi)容,希望通過本文的閱讀你將對?Golang哈希算法有更全面的理解
    2023-05-05

最新評論

江孜县| 淮北市| 大石桥市| 揭西县| 区。| 沙河市| 丹东市| 扶余县| 如皋市| 南靖县| 寻乌县| 会昌县| 连江县| 乐平市| 明溪县| 富阳市| 辛集市| 兰州市| 兴文县| 沾化县| 开封县| 庆安县| 麦盖提县| 剑河县| 蒙城县| 吴桥县| 宁乡县| 苏尼特右旗| 龙南县| 台南县| 封丘县| 积石山| 重庆市| 楚雄市| 林甸县| 娄烦县| 岳阳县| 瑞昌市| 伊宁市| 会泽县| 满洲里市|