Go無緩衝通道的陷阱

2021-08-07 10:46:02 字數 1726 閱讀 5076

channel是go的特色之一,甚至說是最大的特色也不為過,使用起來也非常簡單。

首先定義乙個int型別的channel:

ch1 := make(chan

int) // 無緩衝通道

ch2 := make(chan

int,10) // 帶緩衝的通道

我們這裡主要關注無緩衝通道。

來看看這段**:

package main

import (

"sync"

"fmt"

)func main()

ch1 := make(chan

int)

wg.add(1)

for i :=0; i <10; i++

go func1(ch1, &wg)

wg.wait()

close(ch1)

fmt.println("close channel: ", ch1)

}func func1(ch chan

int, wg *sync.waitgroup) else

}default:

fmt.println("1 got nothing")}}

wg.done()

}

乍眼一看似乎沒毛病,但是當執行程式的時候:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:

main.main()

/users/bruce/code/go/src/gocommonservices/sync-demo/demo.go:19 +0xb9

exit status 2

process finished with

exit code 1

為什麼呢? 仔細看了看上面的程式,在定義了無緩衝通道ch1之後,立馬向其中寫入資料:

ch1 := make(chan int)

fori := 0; i

< 10; i++

但此時並沒有消費者,而無緩衝通道在寫入乙個資料之後,會等待消費者消費,程式阻塞,但啟動消費者的**:

go func1(ch1, &wg)
恰好在for迴圈之後,所以這個goroutine永遠沒有啟動的機會,這就是報錯資訊提示的,deadlock了,要修復這個有兩種方法:

1 ch1定義為緩衝通道,足夠容納for中的資料,就不會阻塞

ch1 := make(chan

int,10)

2 先啟動消費者,再向通道中寫資料
go func1(ch1, &wg) // 先啟動消費者,再向ch1中寫入資料,以防阻塞

ch1 := make(chan

int)

for i :=0; i <10; i++

歸根結底,還是因為channel的特性:

無緩衝的channel,不管是入還是出,都會阻塞,所以在同乙個goroutine中,不能同時對同乙個無緩衝channel進行入和出操作;

帶緩衝的channel,在佇列滿之前,不會阻塞;佇列滿之後,依然會阻塞。

channel無疑是go併發程式開發的利器,但使用的時候還是需要仔細慎重,注意避免像本文提到的這些『陷阱』。

Go 緩衝通道

語法結構 cap為容量 ch make chan type,cap 通道是非同步的,是一種在被建立時就被開闢了能儲存乙個或者多個值的通道。這種型別並不要求傳送與接收同時進行。只要緩衝區有未使用空間用於傳送資料,或還包含可以接收的資料,那麼其通訊就會無阻塞地進行。只有在通道中沒有要接收的值時,接收動作...

go語言通道插入0 Go語言帶緩衝的通道

go語言中有緩衝的通道 bufferedchannel 是一種在被接收前能儲存乙個或者多個值的通道。這種型別的通道並不強制要求goroutine之間必須同時完成傳送和接收。通道會阻塞傳送和接收動作的條件也會不同。只有在通道中沒有要接收的值時,接收動作才會阻塞。只有在通道沒有可用緩衝區容納被傳送的值時...

Go語言帶緩衝的通道實現

go語言中有緩衝的通道 buffered channel 是一種在被接收前能儲存乙個或者多個值的通道。這種型別的通道並不強制要求 goroutine 之間必須同時完成傳送和接收。通道會阻塞傳送和接收動作的條件也會不同。只有在通道中沒有要接收的值時,接收動作才會阻塞。只有在通道沒有可用緩衝區容納被傳送...