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

淺談GO中的Channel以及死鎖的造成

 更新時(shí)間:2022年03月18日 16:02:16   作者:Sirius_7  
本文主要介紹了淺談GO中的Channel以及死鎖的造成,文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

寫(xiě)在前面

這篇文章的誕生要感謝MIT 6.284課程。在其中一節(jié)課中,談到了多線程的協(xié)同的一些問(wèn)題,其中就涉及到了channel這個(gè)概念,并由一段代碼引發(fā)思考并逐漸深入得到了這篇文章。

引子

課程中有一段代碼如下:

在這里插入圖片描述

其大致含義是:代碼背景是在進(jìn)行多線程網(wǎng)絡(luò)爬蟲(chóng)頁(yè)面url,master線程啟動(dòng)后,從channel通道中讀取當(dāng)前頁(yè)面的所有url即urls,接著再對(duì)這個(gè)urls中的每一個(gè)url進(jìn)行爬蟲(chóng)讀取新頁(yè)面中的urls(即執(zhí)行g(shù)o worker(u, ch ,fetcher)),每啟動(dòng)一個(gè)worker線程便開(kāi)始向channel中寫(xiě)入該url指向頁(yè)面中所有包含的urls,以供master線程讀取。

問(wèn)題拋出

那么問(wèn)題來(lái)了,為什么第一層for循環(huán)不會(huì)range完ch之后便直接結(jié)束循環(huán),還需要利用局部變量n來(lái)根據(jù)特定情況跳出循環(huán)?

問(wèn)題解釋

課程上的解釋是,這個(gè)range會(huì)一直阻塞,但并未提出解釋。其實(shí),這里很容易分析,因?yàn)楫?dāng)前的channel是一個(gè)無(wú)緩沖通道。所謂無(wú)緩沖通道,簡(jiǎn)單的講就是兩個(gè)線程對(duì)channel進(jìn)行操作,一個(gè)讀,一個(gè)寫(xiě),永遠(yuǎn)都只能是寫(xiě)一個(gè),讀一個(gè)按照這樣的順序進(jìn)行。更詳細(xì)一些的話,讀的那個(gè)線程會(huì)一直阻塞,直到寫(xiě)的線程向channel中寫(xiě)入一個(gè)數(shù)據(jù)。反之亦然,寫(xiě)的線程在完成一次寫(xiě)操作之后,也會(huì)一直阻塞直到另外一個(gè)線程完成對(duì)該channel的讀取操作。上述情況只有一種例外狀況,那就是該channel通道被某個(gè)線程close掉了:close(channel)。

而這里的range其實(shí)不太等同于對(duì)數(shù)組的range,這里的range實(shí)質(zhì)上為對(duì)channel通道的讀取。所以,在并未有認(rèn)為close通道的前提下,該for循環(huán)會(huì)一直阻塞,不會(huì)退出,于是需要設(shè)定一個(gè)局部狀態(tài)量n讓其退出循環(huán),保證程序的正常運(yùn)行。當(dāng)然我們也可以通過(guò)close其channel來(lái)實(shí)現(xiàn),不過(guò)我認(rèn)為close的時(shí)機(jī)可能不是非常容易把握。

繼續(xù)深入

完成上述思考之后,對(duì)channel進(jìn)行了較為的深入的分析,當(dāng)然分析是以具體的實(shí)驗(yàn)展開(kāi)的。給出下述實(shí)驗(yàn)代碼:

func main() {
    test()
}

func test()  {
	ch := make(chan int,4)

	go func() {
		ch <- 1
		ch <- 2
		ch <- 3
		ch <- 4
	}()

	//go func() {
	for a := range ch {
		fmt.Print(a)
	}
	//}()

	fmt.Print("test is over")
}

執(zhí)行結(jié)果直接報(bào)錯(cuò),顯示:fatal error: all goroutines are asleep - deadlock!
即:出現(xiàn)死鎖。
為什么會(huì)出現(xiàn)這種情況?
首先我們來(lái)分析一下這段代碼的目的:利用channel通道,實(shí)現(xiàn)數(shù)據(jù)的傳遞,一個(gè)線程向channel通道中寫(xiě)入數(shù)據(jù),另外一個(gè)讀取。為什么會(huì)出現(xiàn)死鎖呢?

首先我們分析一下當(dāng)前程序有多少個(gè)線程在執(zhí)行,main函數(shù)是主線程,調(diào)用test函數(shù)之后,主線程進(jìn)入了test函數(shù)中繼續(xù)運(yùn)行。而在test函數(shù)中,采用閉包函數(shù)或者說(shuō)匿名函數(shù)的方法新開(kāi)了一個(gè)線程,即goroutine去向已經(jīng)生成的無(wú)緩沖通道中發(fā)送數(shù)據(jù)。發(fā)送的過(guò)程并非是主線程的任務(wù),所以主線程在執(zhí)行完go func之后馬上跳過(guò)繼續(xù)執(zhí)行下面的for循環(huán),也就是要將channel中的數(shù)據(jù)讀取出來(lái)。

for a := range ch {
		fmt.Print(a)
	}

這時(shí),問(wèn)題來(lái)了。現(xiàn)在兩個(gè)線程,主線程讀,另外一個(gè)寫(xiě)。在另外一個(gè)線程完成最后一個(gè)寫(xiě)之后,主線程開(kāi)始阻塞等待新的寫(xiě)操作,而主線程一旦阻塞整個(gè)test函數(shù)也無(wú)法結(jié)束,所以導(dǎo)致了死鎖的產(chǎn)生,主線程一直被阻塞。

明白了上述原因之后,解決方法便很簡(jiǎn)單了,將從channel中讀數(shù)據(jù)的任務(wù)交給另外一個(gè)線程,而非主線程,主線程直接調(diào)用完test函數(shù)之后馬上結(jié)束,其他兩個(gè)線程的死活都不會(huì)影響到程序本身的運(yùn)行,即主線程的運(yùn)行。如下:

func main() {
    test()
}

func test()  {
	ch := make(chan int,4)

	go func() {
		ch <- 1
		ch <- 2
		ch <- 3
		ch <- 4
	}()

	go func() {
	for a := range ch {
		fmt.Print(a)
	}
	}()

	fmt.Print("test is over")
}

當(dāng)然這種方法是偷懶的,這樣的操作有可能導(dǎo)致內(nèi)存溢出等情況發(fā)生,所以最好還是讓發(fā)送數(shù)據(jù)的線程在發(fā)送完之后將channel關(guān)閉,如下所示:

func main() {
    test()
    time.Sleep(time.Second)
}

func test()  {
	ch := make(chan int,4)

	go func() {
		ch <- 1
		ch <- 2
		ch <- 3
		ch <- 4
		close(ch)
	}()

	go func() {
	for a := range ch {
		fmt.Print(a)
	}
	}()

	fmt.Print("test is over")
}

輸出為:

test is over1234

注意,這里為了保證能夠輸出1234,需要將主線程休眠1s,確保主線程在退出之前,負(fù)責(zé)讀取的線程能夠完成讀取工作。

寫(xiě)在后面

Go語(yǔ)言對(duì)多線程天然的集成性,讓其在處理并發(fā)的一些事務(wù)時(shí)十分方便,但是還是需要注意一些死鎖的生成。

到此這篇關(guān)于淺談GO中的Channel以及死鎖的造成的文章就介紹到這了,更多相關(guān)GO中Channel及死鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang HTTP 服務(wù)器 處理 日志/Stream流的操作

    golang HTTP 服務(wù)器 處理 日志/Stream流的操作

    這篇文章主要介紹了golang HTTP 服務(wù)器 處理 日志/Stream流的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go語(yǔ)言中DateTime的用法介紹

    Go語(yǔ)言中DateTime的用法介紹

    這篇文章介紹了Go語(yǔ)言中DateTime的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • golang雙指針快速排序的實(shí)現(xiàn)代碼

    golang雙指針快速排序的實(shí)現(xiàn)代碼

    這篇文章主要介紹了golang雙指針快速排序的實(shí)現(xiàn)代碼,通過(guò)實(shí)例代碼補(bǔ)充介紹了Golang實(shí)現(xiàn)快速排序和歸并排序以及堆排序算法全注釋,需要的朋友可以參考下
    2024-03-03
  • 解析GOROOT、GOPATH、Go-Modules-三者的關(guān)系

    解析GOROOT、GOPATH、Go-Modules-三者的關(guān)系

    這篇文章主要介紹了解析GOROOT、GOPATH、Go-Modules-三者的關(guān)系,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Go語(yǔ)言獲取文件的名稱(chēng)、前綴、后綴

    Go語(yǔ)言獲取文件的名稱(chēng)、前綴、后綴

    這篇文章主要介紹了Go語(yǔ)言獲取文件的名稱(chēng)、前綴、后綴,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • Go語(yǔ)言使用Request,Response處理web頁(yè)面請(qǐng)求

    Go語(yǔ)言使用Request,Response處理web頁(yè)面請(qǐng)求

    這篇文章主要介紹了Go語(yǔ)言使用Request,Response處理web頁(yè)面請(qǐng)求,需要的朋友可以參考下
    2022-04-04
  • 如何使用proto組件編譯pb.go文件

    如何使用proto組件編譯pb.go文件

    這篇文章主要介紹了如何使用proto組件編譯pb.go文件的詳細(xì)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Go使用協(xié)程交替打印字符

    Go使用協(xié)程交替打印字符

    這篇文章主要介紹了Go使用協(xié)程交替打印字符,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • GO語(yǔ)言中的Map使用方法詳解

    GO語(yǔ)言中的Map使用方法詳解

    這篇文章主要給大家介紹了關(guān)于GO語(yǔ)言中Map使用方法的相關(guān)資料,在go語(yǔ)言中map是散列表的引用,map的類(lèi)型是map[k]v,也就是常說(shuō)的k-v鍵值對(duì),需要的朋友可以參考下
    2023-08-08
  • golang中的net/rpc包使用概述(小結(jié))

    golang中的net/rpc包使用概述(小結(jié))

    本篇文章主要介紹了golang中的net/rpc包使用概述(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11

最新評(píng)論

柳河县| 沂源县| 泉州市| 南部县| 陆良县| 当雄县| 长沙县| 固始县| 永新县| 谷城县| 德钦县| 德兴市| 兴山县| 长泰县| 扶余县| 宜川县| 香格里拉县| 红河县| 南投市| 襄城县| 大安市| 赫章县| 铜鼓县| 崇明县| 富源县| 九台市| 洛川县| 呼玛县| 涞水县| 汤阴县| 三河市| 济南市| 娱乐| 枣阳市| 格尔木市| 庄浪县| 泰和县| 梧州市| 金阳县| 乌鲁木齐县| 西乌珠穆沁旗|