Go語言高能踩坑記錄 通道

2021-10-03 17:17:54 字數 2054 閱讀 7024

使用go通道,經常會遇到死鎖錯誤,根據我所遇到做了以下整理:

fatal error: all goroutines are asleep - deadlock!
看下面這段**

package main

import "fmt"

func main()

執行會丟擲錯誤,如下

fatal error: all goroutines are asleep - deadlock!
上述**中,情況是先往通道中存入資料,再從通道中讀取資料。似乎沒問題,但是對於使用 make 建立通道的時候,若不傳遞第二個引數,則你定義的是無緩衝通道,而對於無緩衝通道,在接收者(stdout)未準備好之前,傳送操作是阻塞的。因此,對於解決此問題有兩種方法:

第一種方法:使接收者**在傳送者之前執行

若要程式正常執行,需要保證接收者程式在傳送資料到通道前就進行阻塞狀態(準備好),修改**如下

package main

import "fmt"

func main()

然而執行的時候還是報同樣的錯誤。問題出在**呢?原來我們將傳送者和接收者寫在了同一協程中,雖然保證了接收者**在傳送者之前執行,但是由於前面接收者一直在等待資料 而處於阻塞狀態,所以無法執行到後面的傳送資料。還是一樣造成了死鎖。

這樣的話,我們可以將接收者**寫在另乙個協程裡,並保證在傳送者之前執行,就像這樣:

package main

import "fmt"

func hello(pipline chan string)  

func main()

執行之後 ,一切正常。

第二種方法使用緩衝通道,而不使用無緩衝通道

接收者**必須在傳送者**之前 執行,這是針對無緩衝通道才有的約束。

既然這樣,我們改使用可緩衝通道不就ok了嗎?

package main

import "fmt"

func main()

執行之後,一切正常。

每個緩衝通道,都有容量,當通道裡的資料量等於通道的容量後,此時再往通道裡傳送資料,就會造成阻塞,必須等到有人從通道中消費資料後,程式才會往下進行。

比如這段**,通道容量為 1,但是往通道中寫入兩條資料,對於乙個協程來說就會造成死鎖。

package main

import "fmt"

func main()

當程式一直在等待從通道裡讀取資料,而此時並沒有人會往通道中寫入資料。此時程式就會陷入死迴圈,造成死鎖。

比如這段**,for 迴圈接收了兩次訊息("hello world"和「hello china」)後,再也沒有人傳送資料了,接收者就會處於乙個等待永遠接收不到資料的囧境。陷入死迴圈,造成死鎖。

package main

import "fmt"

func main() ()

for data := range pipline

}

包子鋪裡的包子已經賣完了,可還有人在排隊等著買,如果不再做包子,就要告訴排隊的人:不用等了,今天的包子已經賣完了,明日請早呀。

不能讓人家死等呀,不跟客人說明一下,人家還以為你們店後面還在蒸包子呢。

所以這個問題,解決方法很簡單,只要在傳送完資料後,手動關閉通道,告訴 range 通道已經關閉,無需等待就行。

package main

import "fmt"

func main() ()

for data := range pipline

}

Go語言容易踩的坑

本文章記錄go學習過程中的一些容易忽視的地方。package main import fmt 會先把defer全部出棧,看有沒有recover defer出完之後,沒有recover,則報錯 func main1 defer func defer func panic 觸發異常 func calc ...

golang chan 踩坑 通道特性

golang 在協程中都會用到chan 用於資料同步,在併發場景下一般都會使用到這個,簡單場景就是乙個讀取,乙個寫入,所以chan都是成對出現的,現在主要來說明一下有緩衝和無緩衝的場景對比。ch1 make chan int 無緩衝 ch2 make chan int,1 有緩衝 ch1 5 無緩衝...

GO語言結構體物件轉JSON踩坑記錄

多說無益 上 第乙個需要注意的地方 響應資料 rsp writecontent,json.marshal rsp recordlog.debug string writecontent w.write writecontent 第一處需要注意 在定義結構體的時候 注意在變數後新增json xx 字串...