go語言通道插入0 Go語言之通道

2021-10-13 08:10:52 字數 2828 閱讀 2637

所以在多個goroutine併發中,我們不僅可以通過原子函式和互斥鎖保證對共享資源的安全訪問,消除競爭的狀態,還可以通過使用通道,在多個goroutine傳送和接受共享的資料,達到資料同步的目的。

通道,它有點像在兩個routine之間架設的管道:乙個goroutine可以往這個管道裡塞資料,另外乙個可以從這個管道裡取資料。有點類似於我們說的佇列。

宣告乙個通道很簡單,我們使用chan關鍵字即可。除此之外,還要指定通道中傳送和接收資料的型別,這樣我們才能知道,要傳送什麼型別的資料給通道,也知道從這個通道裡可以接收到什麼型別的資料。

ch:=make(chan int)

通道型別和map這些型別一樣,可以使用內建的make函式宣告初始化。這裡我們初始化了乙個chan int型別的通道,所以我們只能往這個通道裡傳送int型別的資料,當然接收也只能是int型別的資料。

我們知道,通道是用於在goroutine之間通訊的,它具有傳送和接收兩個操作,而且這兩個操作的運算子都是

ch看例子,慢慢理解傳送和接收的用法。傳送操作

通道我們還可以使用內建的close函式關閉。

close(ch)

如果乙個通道被關閉了,我們就不能往這個通道裡傳送資料了,如果傳送的話,會引起painc異常。但是,我們還可以接收通道裡的資料,如果通道裡沒有資料的話,接收的資料是nil。

剛剛我們使用make函式初始化的時候,只有乙個引數,其實make還可以有第二個引數,用於指定通道的大小。預設沒有第二個引數的時候,通道的大小為 0 ,這種通道也被成為無緩衝通道。

ch:=make(chanint)ch:=make(chanint,0)ch:=make(chanint,2)

看例子,其中第乙個和第二個初始化是等價的。第三個初始化建立了乙個大小為 2 的通道,這種稱為有緩衝通道。

無緩衝的通道

無緩衝的通道指的是通道的大小為 0 。也就是說,這種型別的通道在接收前沒有能力儲存任何值,它要求傳送goroutine和接收goroutine同時準備好,才可以完成傳送和接收操作。

從上面無緩衝的通道定義來看,傳送goroutine和接收gouroutine必須是同步的。同時準備後,如果沒有同時準備好的話,先執行的操作就會阻塞等待,直到另乙個相對應的操作準備好為止。這種無緩衝的通道我們也稱之為同步通道。

func main() 

ch fmt.println(

在前面的例子中,我們為了演示goroutine,防止程式提前終止,都是使用sync.waitgroup進行等待。現在的這個例子就不用了,我們使用同步通道來等待。

在計算sum和的goroutine沒有執行完,把值賦給ch通道之前,fmt.println(

管道~ls|grep'd'desktopdocumentsdownloads

比如上面這個例子的意思是,先使用ls命令,把當前目錄下的目錄和檔案列出來,作為下乙個grep命令的輸入,然後通過grep命令,匹配我們需要顯示的目錄和檔案,這裡匹配以d開頭的檔名或者目錄名。

其實我們使用通道也可以做到管道的效果,我們只需要把乙個通道的輸出,當成下乙個通道的輸入即可。

func main() {

one := make(chan int)

two := make(chan int)

go func() {

onego func() {

v:=two

fmt.println(

這裡例子中我們定義兩個通道one和two,然後按照順序,先把 100 傳送給通道one,然後用另外乙個goroutine從one接收值,再傳送給通道two,最終在主goroutine裡等著接收列印two通道裡的值。這就類似於乙個管道的操作,把通道one的輸出,當成通道two的輸入,類似於接力賽一樣。

有緩衝的通道

有緩衝通道,其實是乙個佇列,這個佇列的最大容量就是我們使用make函式建立通道時,通過第二個引數指定的。

ch := make(chan int, 3)

這裡建立容量為 3 的、有緩衝的通道。對於有緩衝的通道,向其傳送操作就是向佇列的尾部插入元素,接收操作則是從佇列的頭部刪除元素,並返回這個剛剛刪除的元素。

當佇列滿的時候,傳送操作會阻塞;當佇列空的時候,接受操作會阻塞。有緩衝的通道,不要求傳送和接收操作是同步的,相反可以解耦傳送和接收操作。

想知道通道的容量以及裡面有幾個元素資料怎麼辦?其實和map一樣,使用cap和len函式就可以了。

cap(ch)len(ch)

cap函式返回通道的最大容量,len函式返回現在通道裡有幾個元素。

func mirroredquery() string {

responses := make(chan string, 3)

go func() { responses 

go func() { responses 

go func() { responses 

return 

這是go語言聖經裡比較有意義的乙個例子,例子是想獲取服務端的乙個資料,不過這個資料在三個映象站點上都存在,這三個映象分散在不同的地理位置,而我們的目的又是想最快地獲取資料。

所以這裡,我們定義了乙個容量為 3 的通道responses,然後同時發起 3 個併發goroutine向這三個映象獲取資料,獲取到的資料傳送到通道responses中,最後我們使用return

單向通道

有時候,我們有一些特殊場景,比如限制乙個通道只可以接收,但是不能傳送;有時候限制乙個通道只能傳送,但是不能接收,這種通道我們稱為單向通道。

定義單向通道也很簡單,只需要在定義的時候,帶上

varsend chan

注意單向通道應用於函式或者方法的引數比較多,比如:

func counter(outchan

例子這樣的,只能進行傳送操作,防止使用接收操作。如果使用了接收操作,在編譯的時候就會報錯的。

go語言通道插入0 Go 語言通道

51reboot 運維開發 golang 課程 k8s 課程 python 自動化高階課程 python 基礎實戰課程 運維前端課程 課程試聽預約請掃碼 原子函式和互斥函式都能工作,但是依靠它們都不會讓編寫併發程式變得更簡單,更不容易出錯,或者更有趣。在 go 語言裡,你可以使用通道來傳送和接收需要...

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

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

go語言通道插入0 Go 語言的併發性

昨天,我在 quora 上回答了乙個關於 go 語言併發模型的問題。現在,我覺得我還想再多說些什麼!併發性是 go 語言中最強大的特性之一。許多人討論了這個話題,從非常簡單到過於複雜的都有。今天,我也來說說我的看法。go 語言的併發性是一種思維方式而不僅僅是乙個語法。為了利用 go 的強大功能,你需...