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

Golang控制通道實現(xiàn)協(xié)程等待詳解

 更新時間:2022年11月18日 14:45:44   作者:Mingvvv  
這篇文章主要介紹了Golang控制通道實現(xiàn)協(xié)程等待,通道是Go語言程序的并發(fā)體goroutine是它們之間的通信機制。一個通道是一個通信機制,它可以讓一個goroutine通過它給另一個goroutine發(fā)送值信息。每個通道都有一個特殊的類型,也就是channels可發(fā)送數(shù)據(jù)的類型

前言

上一次簡單了解了協(xié)程的工作原理 前文鏈接

最后提到了幾個使用協(xié)程時會遇到的問題,其中一個就是主線程不會等待子線程結(jié)束,在這里記錄兩種比較簡單的方法,并借此熟悉下通道的概念。

方法一-睡眠等待

簡單暴力的解決方案,在創(chuàng)建了子協(xié)程之后,主協(xié)程等待一段時間再結(jié)束。

func goroutineTest(i int) {
	fmt.Println(i)
}
func main() {
	for i := 0; i < 3; i++ {
		go func() {
			fmt.Println(i)
		}()
	}
	//等待一段時間
	time.Sleep(time.Millisecond * 500)
}

簡單暴力但是并不實用,缺點十分明顯, 我們并不知道子協(xié)程什么時候會全部執(zhí)行結(jié)束,要么等待時間太短,要么等待時間太長影響方法執(zhí)行性能。

所以我們需要其他更靈活的方式。

方法二-通道

什么是通道

通道是 Go 自帶的、唯一的可以滿足并發(fā)安全的類型,通道相當(dāng)于是一個先進先出的隊列,通道中的元素會按照插入進來時候的順序再發(fā)送出去。

通道的特性

一、進出通道的值都是副本數(shù)據(jù)

當(dāng)向通道內(nèi)傳值時,傳遞的其實是原本元素的副本,移動時也是同理。

二、對于同一個通道,發(fā)送操作之間是互斥的,接收操作之間也是互斥的。

當(dāng)有操作要向通道發(fā)送數(shù)據(jù)的時候,其他操作的發(fā)送處理會被阻塞,只有當(dāng)前面的操作執(zhí)行完畢,值完全被復(fù)制進通道內(nèi)之后,后面的操作才可以發(fā)送。接收通道里的值也是同理,只有當(dāng)值被接受,且元素在通道內(nèi)被刪除之后,其他的接受操作才能被執(zhí)行。

三、對于同一個通道同一元素值來說,發(fā)送和接受操作也是互斥的。

因為上面提到元素進出通道是通過副本的方式,這樣做可以避免出現(xiàn)復(fù)制還未完成就有操作將其取走的情況。

四、發(fā)送操作和接收操作中對元素值的處理是絕對完整的。

發(fā)送至通道的操作時,絕不會出現(xiàn)只復(fù)制一部分的情況,同理接收通道時,通道在準(zhǔn)備好元素值的副本之后一定會將通道內(nèi)的原值刪除。

五、發(fā)送和接受操作在未完成之前會一直阻塞

其實就是為了實現(xiàn)操作的互斥和元素值的完整。

什么是非緩沖通道

無緩沖隊列表示長度為 0 的通道,長度為 0 表示這個通道不能保留信息,數(shù)據(jù)是直接從發(fā)送方復(fù)制到接收方,當(dāng)有信息傳進來時,發(fā)送方會阻塞,直到有接收方接受這個值,當(dāng)然我們也可以先找到一個接收方去接收(但是這里有個坑>>>需要注意死鎖)。

什么是緩沖通道

緩沖隊列就是表示長度大于 0 的通道,這里的通道相當(dāng)于一個中轉(zhuǎn)倉庫。如果通道滿了,那么對它的所有發(fā)送操作都會被阻塞,直到通道中有元素值被接收走,通道會優(yōu)先通知最早因此在等待的發(fā)送操作。同理,如果通道已空,那么對它的所有接收操作都會被阻塞,直到通道中有新的元素值出現(xiàn)。這時,通道會通知最早等待的那個接收操作。

通道的簡單使用

  • 在聲明通道時,我們要定義通道內(nèi)元素的類型 chan [type]
  • <- 是發(fā)送至通道和接收通道元素的操作符,通道在左側(cè)表示向通道內(nèi)發(fā)送,通道在右側(cè)表示從通道內(nèi)接收
  • 通道定義之后,一定要初始化,對于沒有進行初始化的通道,發(fā)送和接收操作都是阻塞的

非緩沖通道

定義一個非緩沖通道,通道內(nèi)元素類型為 int
var ch0 = make(chan int)
func set() {
	for i := 0; i < 3; i++ {
		time.Sleep(time.Millisecond * 1000)
		fmt.Println(i)
	}
	ch0 <- 999
}
func main() {
	//val := <-ch0
	go set()
	fmt.Println("work in here")
	val2 := <-ch0
	fmt.Println("get value")
	fmt.Println(val2)
	fmt.Println("work finished")
}

這段代碼主協(xié)程中先開啟了一個子協(xié)程,然后從通道中接受一個值,并打印出來,運行結(jié)果如下。

主協(xié)程執(zhí)行到 val2 := <-ch0 這一行時發(fā)生了阻塞,三秒過后子協(xié)程向通道中發(fā)送了元素值。主協(xié)程從通道中接收到了值,然后繼續(xù)向下走。

work in here
0
1
2
get value
999
work finished

緩沖通道

func main() {
  定義一個大小為?。场〉耐ǖ?
	chn := make(chan int, 3)
	chn <- 1
	chn <- 2
	chn <- 3
	fmt.Printf("get value: %v\n", <-chn)
	fmt.Printf("get value: %v\n", <-chn)
	fmt.Printf("get value: %v\n", <-chn)
}

get value: 1
get value: 2
get value: 3

小心死鎖

有一個需要注意的地方,如果我們把非緩沖通道示例代碼中主協(xié)程方法中的第一行代碼解開注釋再運行,會發(fā)現(xiàn)程序出現(xiàn)了報錯。

表示所有的協(xié)程都睡眠了,發(fā)生了死鎖。

fatal error: all goroutines are asleep - deadlock!

其實原因也很簡單,就比如那上面的代碼來說。我們上來就在主協(xié)程中接收通道中的值,而此時通道中沒有值,所以主協(xié)程會阻塞,然而此時我們并沒有開啟其他的協(xié)程,那就相當(dāng)于這個程序后面將不會有沒有任何操作,永遠鎖在了這個位置。所以如果在阻塞期間發(fā)現(xiàn)沒有正在執(zhí)行的協(xié)程,程序?qū)⒈霎惓M顺觥?/p>

所以我們在對通道進行操作時,要注意千萬不要在邏輯上把自己鎖死了。

使用通道實現(xiàn)協(xié)程等待

用起來有點像 JAVA 中的 CountDownLatch

  • 首先我們需要知道子協(xié)程的數(shù)量 num
  • 然后我們創(chuàng)建一個大小為 num 的通道
  • 當(dāng)子協(xié)程完全執(zhí)行完之后就向通道中放一個元素值
  • 主協(xié)程從通道中循環(huán)取值,取值的次數(shù)就是 num,取不到值時會阻塞,而這 num 個值只有當(dāng)全部子協(xié)程都執(zhí)行完畢之后才能提供全,所以這樣就實現(xiàn)了主協(xié)程等待子協(xié)程

至于為什么要創(chuàng)建 struct{} 類型的通道,是因為空結(jié)構(gòu)體占用了0字節(jié)的內(nèi)存空間

func main() {
	num := 5
	sign := make(chan struct{}, num)
	for i := 0; i < num; i++ {
		go func() {
			fmt.Println(i)
			sign <- struct{}{}
		}()
	}
	for j := 0; j < num; j++ {
		<-sign
	}
}

到此這篇關(guān)于Golang控制通道實現(xiàn)協(xié)程等待詳解的文章就介紹到這了,更多相關(guān)Go協(xié)程等待內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go通過goroutine實現(xiàn)多協(xié)程文件上傳的基本流程

    Go通過goroutine實現(xiàn)多協(xié)程文件上傳的基本流程

    多協(xié)程文件上傳是指利用多線程或多協(xié)程技術(shù),同時上傳一個或多個文件,以提高上傳效率和速度,本文給大家介紹了Go通過goroutine實現(xiàn)多協(xié)程文件上傳的基本流程,需要的朋友可以參考下
    2024-05-05
  • Go語言中的數(shù)據(jù)格式(json、xml?、msgpack、protobuf)使用總結(jié)

    Go語言中的數(shù)據(jù)格式(json、xml?、msgpack、protobuf)使用總結(jié)

    在分布式的系統(tǒng)中,因為涉及到數(shù)據(jù)的傳輸,所以一定會進行數(shù)據(jù)的交換,此時就要定義數(shù)據(jù)交換的格式,例如二進制、Json、Xml等等。本文總結(jié)了Go語言中的數(shù)據(jù)格式,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • Golang中Gin框架中如何定義路由詳解

    Golang中Gin框架中如何定義路由詳解

    Gin是一個用Go語言編寫的Web框架,具有高性能和易于使用的特點,本文將結(jié)合實際案例,詳細介紹Gin框架的路由用法,有需要的小伙伴可以參考下
    2024-10-10
  • Go語言中利用http發(fā)起Get和Post請求的方法示例

    Go語言中利用http發(fā)起Get和Post請求的方法示例

    這篇文章主要給大家介紹了關(guān)于Go語言中利用http發(fā)起Get和Post請求的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • 詳解golang 定時任務(wù)time.Sleep和time.Tick實現(xiàn)結(jié)果比較

    詳解golang 定時任務(wù)time.Sleep和time.Tick實現(xiàn)結(jié)果比較

    本文主要介紹了golang 定時任務(wù)time.Sleep和time.Tick實現(xiàn)結(jié)果比較,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 基于go+vue實現(xiàn)的golang每日新聞數(shù)據(jù)瀏覽與檢索平臺(推薦)

    基于go+vue實現(xiàn)的golang每日新聞數(shù)據(jù)瀏覽與檢索平臺(推薦)

    gonews是基于 go+vue 實現(xiàn)的golang每日新聞瀏覽與檢索平臺,本文通過實例代碼給大家講解,介紹的非常詳細,具有參考借鑒價值,需要的朋友參考下吧
    2018-01-01
  • Go實現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱)

    Go實現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱)

    這篇文章給大家介紹了Go實現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱),需求很簡單,就是用戶輸入自己的郵箱后,使用官方郵箱給用戶發(fā)送替郵件模版,文中有詳細的代碼示例供大家參考,需要的朋友可以參考下
    2023-10-10
  • 關(guān)于golang中平行賦值淺析

    關(guān)于golang中平行賦值淺析

    這篇文章主要給大家介紹了關(guān)于golang中平行賦值的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用golang具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • 深入淺出go依賴注入工具Wire的使用

    深入淺出go依賴注入工具Wire的使用

    但隨著項目規(guī)模的增長,組件之間的依賴關(guān)系變得復(fù)雜,手動管理可能會很繁瑣,所以本文將深入探討一個備受歡迎的?Go?語言依賴注入工具——?Wire,感興趣的可以了解下
    2023-09-09
  • go中import包的大坑解決方案

    go中import包的大坑解決方案

    最近開始使用Go/GoLand 在import 自定義包時出現(xiàn)各種狀況,本文就介紹一下go中import包的大坑解決方案,具有一定的參考價值,感興趣 可以了解一下
    2022-06-06

最新評論

缙云县| 寿阳县| 宜丰县| 和林格尔县| 榕江县| 彭阳县| 文成县| 东明县| 茌平县| 鄂州市| 泰宁县| 商河县| 雅江县| 驻马店市| 青龙| 乐陵市| 江源县| 昌吉市| 祁阳县| 奉贤区| 山阴县| 玉树县| 桑日县| 连州市| 德保县| 嵊泗县| 万全县| 罗江县| 曲沃县| 孟州市| 南投市| 婺源县| 阿拉尔市| 寿光市| 延庆县| 佛冈县| 新竹市| 南平市| 固原市| 临西县| 锡林浩特市|