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

Go中sync?包Cond使用場景分析

 更新時(shí)間:2023年03月03日 14:50:04   作者:水淹萌龍  
Cond?是和某個(gè)條件相關(guān),在條件還沒有滿足的時(shí)候,所有等待這個(gè)條件的協(xié)程都會(huì)被阻塞住,只有這個(gè)條件滿足的時(shí)候,等待的協(xié)程才可能繼續(xù)進(jìn)行下去,這篇文章主要介紹了Go中sync?包的Cond使用場景分析,需要的朋友可以參考下

背景

編寫代碼過程中, 通常有主協(xié)程和多個(gè)子協(xié)程進(jìn)行協(xié)作的過程,比如通過 WaitGroup 可以實(shí)現(xiàn)當(dāng)所有子協(xié)程完成之后, 主協(xié)程再繼續(xù)執(zhí)行, 具體可參考:Go 中g(shù)oroutine和WaitGroup的使用

如上的場景是主協(xié)程等待子協(xié)程達(dá)到某個(gè)狀態(tài)再繼續(xù)運(yùn)行。 但是反過來怎么操作呢,要求一組子協(xié)程等待主協(xié)達(dá)到某個(gè)狀態(tài)時(shí)才繼續(xù)運(yùn)行。這個(gè)時(shí)候就需要用到 Cond 了

Cond 簡介

Cond 是和某個(gè)條件相關(guān),在條件還沒有滿足的時(shí)候,所有等待這個(gè)條件的協(xié)程都會(huì)被阻塞住,只有這個(gè)條件滿足的時(shí)候,等待的協(xié)程才可能繼續(xù)進(jìn)行下去。
Cond 在初始化的時(shí)候,需要關(guān)聯(lián)一個(gè) Locker 接口的實(shí)例,一般會(huì)使用 Mutex 或者 RWMutex。
Cond 關(guān)聯(lián)的 Locker 實(shí)例可以通過 c.L 訪問,它內(nèi)部維護(hù)著一個(gè)先入先出的等待隊(duì)列。
Cond 分別有三個(gè)方法

  • Wait

會(huì)把當(dāng)前協(xié)程放入Cond的等待隊(duì)列中并阻塞,直到被Signal或者Broadcast方法從等待隊(duì)列中移除并喚醒,用于子協(xié)程阻塞。

  • Signal

主協(xié)程喚醒等待隊(duì)列中的一個(gè)子協(xié)程,先喚醒最先阻塞的子協(xié)程,被喚醒的子協(xié)程繼續(xù)執(zhí)行。

  • Broadcast

主協(xié)程喚醒等待隊(duì)列中的全部協(xié)程,所有子協(xié)程繼續(xù)執(zhí)行。

注意:調(diào)用Signal和Broadcast方法,不強(qiáng)求持有c.L的鎖,調(diào)用Wait方法是必須要持有c.L的鎖。

使用示例

Signal的使用場景

大家都去醫(yī)院先排隊(duì),然后等待叫號,先排隊(duì)的先叫號。這次模擬有5個(gè)病人,分別先排隊(duì)。 然后護(hù)士根據(jù)排隊(duì)先后來叫號;
具體場景是,5個(gè)病人在三秒中之內(nèi)分別排號,護(hù)士今天要叫5個(gè)號,一秒叫一個(gè),叫完5個(gè)號就結(jié)束了
代碼如下:

package main
import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func main() {
	c := sync.NewCond(&sync.Mutex{})
	num := 0
	// 當(dāng)前叫號是幾號
	hand_num := 0
	for i := 0; i < 5; i++ {
		go func(i int) {
			// 分別在不同時(shí)間排隊(duì)
			time.Sleep(time.Second * time.Duration(rand.Int63n(10)))
			c.L.Lock()
			num++
			// 當(dāng)前取得號。
			cur := num
			fmt.Printf("%s  %d 號病人取到了 %d 號\n", time.Now().Format("2006-01-02 15:04:05"), i, cur)
			// 取到號了,等待叫號
			c.Wait()
			fmt.Printf("%s  %d 號病人排隊(duì)號是 %d 號,被叫號了\n", time.Now().Format("2006-01-02 15:04:05"), i, cur)
			hand_num = cur
			c.L.Unlock()
		}(i)
	}

	// 都叫號了
	for hand_num != 5 {
		// 叫號
		c.Signal()
		time.Sleep(time.Second * 1)
	}

	time.Sleep(time.Second * 10)
}

執(zhí)行結(jié)果如下

在這里插入圖片描述

結(jié)果表明,5個(gè)病人,分別在三秒鐘內(nèi)先后取號, 然后護(hù)士每過一秒鐘按照排隊(duì)的先后順序叫一個(gè)號(叫號的過程依然有病人取號),先取號的被先叫號。
此場景中,5個(gè)病人相當(dāng)于5個(gè)協(xié)程, 主協(xié)程反復(fù)使用Signal() 按照順序一個(gè)個(gè)喚醒阻塞的子協(xié)程。

Broadcast的使用場景

場景為如下: 運(yùn)動(dòng)員跑步比賽,要求8秒內(nèi)全部運(yùn)動(dòng)員準(zhǔn)備好,然后等待教練發(fā)令, 教練10秒后發(fā)令,所有運(yùn)動(dòng)員在發(fā)令后開始跑。

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func main() {
	c := sync.NewCond(&sync.Mutex{})

	for i := 0; i < 10; i++ {
		go func(i int) {
			// 隨機(jī)一個(gè)8秒內(nèi)的準(zhǔn)備時(shí)間
			time.Sleep(time.Second * time.Duration(rand.Int63n(8)))
			fmt.Printf("%s 運(yùn)動(dòng)員%d已準(zhǔn)備就緒\n", time.Now().Format("2006-01-02 15:04:05"), i)
			c.L.Lock()
			// 準(zhǔn)備完畢,等待教練發(fā)令
			c.Wait()
			c.L.Unlock()
			fmt.Printf("%s 運(yùn)動(dòng)員%d開跑\n", time.Now().Format("2006-01-02 15:04:05"), i)
		}(i)
	}

	// 主協(xié)程等待10秒后發(fā)令
	time.Sleep(time.Second * 10)
	fmt.Printf("%s 教練發(fā)令。\n", time.Now().Format("2006-01-02 15:04:05"))
	// 教練發(fā)令。通知所有運(yùn)動(dòng)員開始跑步, 即喚起之前 wait()的所有協(xié)程
	c.Broadcast()
	// 等待跑步
	time.Sleep(time.Second * 5)
}

執(zhí)行結(jié)果如下:

如結(jié)果所示, 10個(gè)運(yùn)動(dòng)員在8秒內(nèi)分別準(zhǔn)備好,等待教練發(fā)令后,同時(shí)開跑。
此場景中,10個(gè)運(yùn)動(dòng)員相當(dāng)于10個(gè)協(xié)程, 同時(shí)等待主協(xié)程的命令,使用Broadcast() 喚醒所有阻塞的子協(xié)程。

注意事項(xiàng)

使用 Cond,最容易踩的坑就是調(diào)用 Wait() 方法之前,調(diào)用者沒有持有鎖或沒有檢查輔助條件。
在如上示例代碼中,假如把調(diào)用 Wait() 方法前后的加鎖和釋放鎖的代碼注釋掉,運(yùn)行代碼會(huì)導(dǎo)致程序 panic。原因是調(diào)用 Wait 方法,會(huì)先把調(diào)用者放入等待隊(duì)列中,然后釋放鎖。此時(shí)如果在未持有鎖時(shí)調(diào)用釋放鎖的方法,就會(huì)導(dǎo)致程序 panic。

到此這篇關(guān)于Go中sync 包的 Cond 使用的文章就介紹到這了,更多相關(guān)go sync包c(diǎn)ond使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言中g(shù)o?mod?vendor使用方法

    Go語言中g(shù)o?mod?vendor使用方法

    go mod vendor的功能是將新增的依賴包自動(dòng)寫入當(dāng)前項(xiàng)目的 vendor目錄,下面這篇文章主要給大家介紹了關(guān)于Go語言中g(shù)o?mod?vendor使用的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • 解決Go中使用seed得到相同隨機(jī)數(shù)的問題

    解決Go中使用seed得到相同隨機(jī)數(shù)的問題

    這篇文章主要介紹了Go中使用seed得到相同隨機(jī)數(shù)的問題,需要的朋友可以參考下
    2019-10-10
  • Go 語言下基于Redis分布式鎖的實(shí)現(xiàn)方式

    Go 語言下基于Redis分布式鎖的實(shí)現(xiàn)方式

    本篇文章將詳細(xì)介紹如何正確地實(shí)現(xiàn)Redis分布式鎖,下面通過一個(gè)項(xiàng)目基于 Redis 的分布式鎖能夠提供哪些分布鎖特性,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-06-06
  • go語言的工作空間和GOPATH環(huán)境變量介紹

    go語言的工作空間和GOPATH環(huán)境變量介紹

    這篇文章主要介紹了go語言的工作空間和GOPATH環(huán)境變量介紹,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang如何快速構(gòu)建一個(gè)CLI小工具詳解

    Golang如何快速構(gòu)建一個(gè)CLI小工具詳解

    這篇文章主要為大家介紹了Golang如何快速構(gòu)建一個(gè)CLI小工具詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 如何在Go中使用切片容量和長度

    如何在Go中使用切片容量和長度

    這篇文章主要介紹了如何在Go中使用切片容量和長度,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • go與go mod命令使用方式以及遇到的問題

    go與go mod命令使用方式以及遇到的問題

    這篇文章主要介紹了go與go mod命令使用方式以及遇到的問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • go實(shí)現(xiàn)自動(dòng)復(fù)制U盤小工具demo

    go實(shí)現(xiàn)自動(dòng)復(fù)制U盤小工具demo

    這篇文章主要為大家介紹了go實(shí)現(xiàn)自動(dòng)復(fù)制U盤小工具demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Go語言的匿名字段實(shí)現(xiàn)組合復(fù)用實(shí)例探究

    Go語言的匿名字段實(shí)現(xiàn)組合復(fù)用實(shí)例探究

    這篇文章主要為大家介紹了Go語言的匿名字段實(shí)現(xiàn)組合復(fù)用實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 基于go interface{}==nil 的幾種坑及原理分析

    基于go interface{}==nil 的幾種坑及原理分析

    這篇文章主要介紹了基于go interface{}==nil 的幾種坑及原理分析,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04

最新評論