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

詳解Golang并發(fā)控制的三種方案

 更新時間:2024年06月19日 09:12:00   作者:拔劍縱狂歌  
本文主要介紹了詳解Golang并發(fā)控制的三種方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

Channel

Channel是Go在語言層面提供的一種協(xié)程間的通信方式,我們可以通過在協(xié)程中向管道寫入數(shù)據(jù)和在待等待的協(xié)程中讀取對應協(xié)程的次數(shù)來實現(xiàn)并發(fā)控制。

func main() {
    intChan := make(chan int, 5)
    waitCount := 5
    for i := 0; i < waitCount; i++ {
       go func() {
          intChan <- 1
       }()
    }

    for i := 0; i < waitCount; i++ {
       <-intChan

    }
    fmt.Println("主進程結束")
}

WaitGroup

waitgroup通常應用于等待一組“工作協(xié)程”結束的場景,waitgroup底層是由一個長度為3的數(shù)組實現(xiàn)的,其內(nèi)部有兩個計數(shù)器,一個是工作協(xié)程計數(shù)器、一個是坐等協(xié)程計數(shù)器,還有一個是信號量。工作協(xié)程全部運行結束后,工作協(xié)程計數(shù)器將置為0,會釋放對應坐等協(xié)程次數(shù)的信號量。

兩點注意:

  • Add()方法中的參數(shù)大小要于工作協(xié)程的數(shù)量相等,否則會導致坐等協(xié)程一直等待,觸發(fā)死鎖panic

  • Done()方法執(zhí)行的次數(shù)要與Add()方法中的工作協(xié)程計數(shù)器的數(shù)量一致,否則當工作協(xié)程計數(shù)器<0時,會觸發(fā)panic【panic: sync: negative WaitGroup counter】

func main() {
    wg := sync.WaitGroup{}
    wg.Add(2)
    go func() {
       time.Sleep(3 * time.Second)
       fmt.Println("等待三分鐘的協(xié)程結束了")
       wg.Done()
    }()

    go func() {
       time.Sleep(3 * time.Second)
       fmt.Println("等待三分鐘的協(xié)程結束了")
       wg.Done()
    }()

    wg.Wait()
}

Context

適用于一個協(xié)程派生出多個協(xié)程的情況,可以控制多級的goroutine。我們可以通過一個Context對象,對派生出來的樹狀goroutine進行統(tǒng)一管理,并且每個goroutine具有相同的上下文。做統(tǒng)一關閉操作、統(tǒng)一定時關閉、統(tǒng)一傳值的操作。多個上下文協(xié)程之間可以互相嵌套配合。

golang實現(xiàn)了四種原生的上下文對象

  • emptyCtx: 該上下文對象一般是作為父節(jié)點的,如果沒有父節(jié)點,我們通常使用context.Background()方法來獲取emptyCtx對象,并將其作為創(chuàng)建其他節(jié)點的父節(jié)點。

  • cancelCtx: 該上下文對象可以關閉所有擁有同一個上下文的goroutine,通過在子協(xié)程中監(jiān)聽cancelCtx.Done方法,來結束所有的派生協(xié)程。具體代碼看下方,我們通過WithCancel()方法來獲取該對象。

  • timerCtx:該上下文對象是對cancelCtx對象的進一步封裝,比cancelCtx主動關閉之外,多了了一個定時關閉功能。我們可以通過WithTimeout()和WithDeadline()這兩種方法來獲取該對象。其中WithTimeout()和WithDeadline()這兩種方法點是WithTimeout()是設置過一段時間關閉上下文,WithDeadline()是設置那一個時間點來關閉這一個上下文。

  • valueCtx:該上下文對象并不用于進行協(xié)程的控制,而是在多級協(xié)程之間進行值得傳遞,方便共享一些相同得上下文內(nèi)容。

以上除emptyCtx外的上下文對象和獲取實例的方法如下圖所示:

 Context示例代碼

cancelCtx

我們在所有的派生協(xié)程中傳入相同的cancelContext對象,并在每一個子協(xié)程中使用switch-case結構監(jiān)聽上下文對象是否關閉,如果上下文對象關閉了,ctx.Done()返回的管道就可以讀取到一個元素,使所在的case語句可執(zhí)行,之后退出switch結構,執(zhí)行協(xié)程中的其他代碼。

func main() {
	ctx, cancelFunc := context.WithCancel(context.Background())
	deadline, ok := ctx.Deadline()
	fmt.Println(deadline, ok)
	done := ctx.Done()
	fmt.Println(reflect.TypeOf(done))
	fmt.Println(done)

	go HandelRequest(ctx)
	//<-done 阻塞當前一層的goroutine
	time.Sleep(5 * time.Second)
	fmt.Println("all goroutines is stopping!")
	cancelFunc()
	err := ctx.Err()
	fmt.Println(err) //context canceled
	time.Sleep(5 * time.Second)
}

func HandelRequest(ctx context.Context) {
	go WriteMysql(ctx)
	go WriteRedis(ctx)
	for {
		select {
		case <-ctx.Done():
			fmt.Println("HandelRequest Done")
			return
		default:
			fmt.Println("等一等,Handler正在執(zhí)行中")
			time.Sleep(2 * time.Second)
		}
	}
}

func WriteRedis(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("WriteRedis Done.")
			return
		default:
			fmt.Println("等一等,Redis正在執(zhí)行中")
			time.Sleep(2 * time.Second)
		}
	}
}

func WriteMysql(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("WriteMysql Done.")
			return
		default:
			fmt.Println("等一等,Mysql正在執(zhí)行中")
			time.Sleep(2 * time.Second)
		}
	}
}

timerCtx

這里代碼以WithTimeout舉例,相比與我們之前的手動調(diào)用關閉,使用timerCtx定時上下文對象后,可以是實現(xiàn)到達指定的時間自動進行關閉的操作。

func main() {
	deadline, _ := context.WithTimeout(context.Background(), 5*time.Second)
	go HandelRequest(deadline)

	time.Sleep(10 * time.Second)

}

func HandelRequest(ctx context.Context) {
	go WriteMysql(ctx)
	go WriteRedis(ctx)
	for {
		select {
		case <-ctx.Done():
			fmt.Println("HandelRequest Done")
			return
		default:
			fmt.Println("等一等,Handler正在執(zhí)行中")
			time.Sleep(2 * time.Second)
		}
	}
}

func WriteRedis(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("WriteRedis Done.")
			return
		default:
			fmt.Println("等一等,Redis正在執(zhí)行中")
			time.Sleep(2 * time.Second)
		}
	}
}

func WriteMysql(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("WriteMysql Done.")
			return
		default:
			fmt.Println("等一等,Mysql正在執(zhí)行中")
			time.Sleep(2 * time.Second)
		}
	}
}

valueCtx

我們可以通過嵌套WithValue上下文,來進行多個key-value在派生協(xié)程中傳遞,共享常量

func main() {
	ctx, cancelFunc := context.WithCancel(context.Background())
	value1 := context.WithValue(ctx, "param1", 1)
	value2 := context.WithValue(value1, "param2", 2)
	go ReadContextValue(value2)

	time.Sleep(10 * time.Second)
	cancelFunc()
	time.Sleep(5 * time.Second)
}

func ReadContextValue(ctx context.Context) {
	fmt.Println(ctx.Value("param1"))
	fmt.Println(ctx.Value("param2"))
}

到此這篇關于詳解Golang并發(fā)控制的三種方案的文章就介紹到這了,更多相關Golang并發(fā)控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • golang如何實現(xiàn)mapreduce單進程版本詳解

    golang如何實現(xiàn)mapreduce單進程版本詳解

    這篇文章主要給大家介紹了關于golang如何實現(xiàn)mapreduce單進程版本的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2018-01-01
  • Golang try catch與錯誤處理的實現(xiàn)

    Golang try catch與錯誤處理的實現(xiàn)

    社區(qū)不少人在談論 golang 為毛不用try/catch模式,而采用苛刻的recovery、panic、defer組合,本文就來詳細的介紹一下,感興趣的可以了解一下
    2021-07-07
  • 詳解golang中的結構體編解碼神器Mapstructure庫

    詳解golang中的結構體編解碼神器Mapstructure庫

    mapstructure是GO字典(map[string]interface{})和Go結構體之間轉(zhuǎn)換的編解碼工具,這篇文章主要為大家介紹一下Mapstructure庫的相關使用,希望對大家有所幫助
    2023-09-09
  • Go語言帶緩沖的通道實現(xiàn)

    Go語言帶緩沖的通道實現(xiàn)

    這篇文章主要介紹了Go語言帶緩沖的通道實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • Go channel實現(xiàn)原理分析

    Go channel實現(xiàn)原理分析

    Channel是go語言內(nèi)置的一個非常重要的特性,也是go并發(fā)編程的兩大基石之一,下面這篇文章主要給大家介紹了關于Go中channel的相關資料,需要的朋友可以參考下
    2023-04-04
  • Go語言常見錯誤之誤用init函數(shù)實例解析

    Go語言常見錯誤之誤用init函數(shù)實例解析

    Go語言中的init函數(shù)為開發(fā)者提供了一種在程序正式運行前初始化包級變量的機制,然而,由于init函數(shù)的特殊性,不當?shù)厥褂盟赡芤鹨幌盗袉栴},本文將深入探討如何有效地使用init函數(shù),列舉常見誤用并提供相應的避免策略
    2024-01-01
  • Golang WaitGroup實現(xiàn)原理解析

    Golang WaitGroup實現(xiàn)原理解析

    WaitGroup是Golang并發(fā)的兩種方式之一,一個是Channel,另一個是WaitGroup,下面這篇文章主要給大家介紹了關于golang基礎之waitgroup用法以及使用要點的相關資料,需要的朋友可以參考下
    2023-02-02
  • 探索Go語言中的switch高級用法

    探索Go語言中的switch高級用法

    在Go語言中,switch語句除了常見的用法外,還有一種不常用但有趣的寫法,這種寫法中,switch后面不跟任何表達式,而每個case后面跟的是返回bool類型的函數(shù)調(diào)用表達式,這實際上是一個等價于switch true的用法,通過從上到下逐一比較case后的表達式是否為true來決定執(zhí)行哪個分支
    2024-10-10
  • Go語言中常量的實現(xiàn)

    Go語言中常量的實現(xiàn)

    Go語言支持單常量和多常量的定義方法,通過const關鍵字實現(xiàn),常量用于存儲不變的值,如圓周率或固定的錯誤信息,旨在提高代碼的維護性和可讀性,感興趣的可以了解一下
    2024-10-10
  • Golang中的archive/zip包的常用函數(shù)詳解

    Golang中的archive/zip包的常用函數(shù)詳解

    Golang 中的 archive/zip 包用于處理 ZIP 格式的壓縮文件,提供了一系列用于創(chuàng)建、讀取和解壓縮 ZIP 格式文件的函數(shù)和類型,下面小編就來和大家講解下常用函數(shù)吧
    2023-08-08

最新評論