go語言高併發channel詳解

2021-08-22 16:33:14 字數 2816 閱讀 5241

go語言中channel可以理解是乙個先進先出的佇列,通過管道進行通訊。

csp 模型:傳統的併發模型主要分為 actor 模型和 csp 模型,csp 模型全稱為 communicating sequential processes,csp 模型由併發執行實體(程序,執行緒或協程),和訊息通道組成,實體之間通過訊息通道傳送訊息進行通訊。和 actor 模型不同,csp 模型關注的是訊息傳送的載體,即通道,而不是傳送訊息的執行實體。

它的操作符是箭頭 <- 。

ch <- v // 傳送值v到channel ch中

v := <-ch // 從channel ch中接收資料,並將資料賦值給v

(箭頭的指向就是資料的流向)

就像 map 和 slice 資料型別一樣, channel必須先建立再使用:

ch := make(chan int)

channel型別的定義格式如下:

channeltype = ( "chan" | "chan" "<-" | "<-" "chan" ) elementtype .
它包括三種型別的定義。可選的<-代表channel的方向。如果沒有指定方向,那麼channel就是雙向的,既可以接收資料,也可以傳送資料。

chan t          // 可以接收和傳送型別為 t 的資料

chan<- float64 // 只可以用來傳送 float64 型別的資料

<-chan int // 只可以用來接收 int 型別的資料

<-總是優先和最左邊的型別結合。(the <- operator associates with the leftmost chan possible)

chan<- chan int // 等價 chan<- (chan int)

chan<- <-chan int // 等價 chan<- (<-chan int)

<-chan <-chan int // 等價 <-chan (<-chan int)

chan (<-chan int)

使用make初始化channel,並且可以設定容量:

make(chan int, 100)

容量(capacity)代表channel容納的最多的元素的數量,代表channel的快取的大小。

如果沒有設定容量,或者容量設定為0, 說明channel沒有快取,只有sender和receiver都準備好了後它們的通訊(communication)才會發生(blocking)。如果設定了快取,就有可能不發生阻塞, 只有buffer滿了後 send才會阻塞, 而只有快取空了後receive才會阻塞。乙個nil channel不會通訊。

可以通過內建的close方法可以關閉channel。

你可以在多個goroutine從/往 乙個channel 中 receive/send 資料, 不必考慮額外的同步措施。

channel可以作為乙個先入先出(fifo)的佇列,接收的資料和傳送的資料的順序是一致的。

channel的 receive支援 multi-valued assignment,如

v, ok := <-ch

它可以用來檢查channel是否已經被關閉了。

send語句

send語句用來往channel中傳送資料, 如ch <- 3。

它的定義如下:

sendstmt = channel 「<-」 expression .

channel = expression .

在通訊(communication)開始前channel和expression必選先求值出來(evaluated),比如下面的(3+4)先計算出7然後再傳送給channel。

c := make(chan int)

defer close(c)

go func() ()

i := <-c

fmt.println(i)

send被執行前(proceed)通訊(communication)一直被阻塞著。如前所言,無快取的channel只有在receiver準備好後send才被執行。如果有快取,並且快取未滿,則send會被執行。

往乙個已經被close的channel中繼續傳送資料會導致run-time panic。

往nil channel中傳送資料會一致被阻塞著。

receive 操作符

<-ch用來從channel ch中接收資料,這個表示式會一直被block,直到有資料可以接收。

從乙個nil channel中接收資料會一直被block。

從乙個被close的channel中接收資料不會被阻塞,而是立即返回,接收完已傳送的資料後會返回元素型別的零值(zero value)。

如前所述,你可以使用乙個額外的返回引數來檢查channel是否關閉。

x, ok := <-ch

x, ok = <-ch

var x, ok = <-ch

如果ok 是false,表明接收的x是產生的零值,這個channel被關閉了或者為空。

import "fmt"

func sum(s int, c chan int)

c <- sum // send sum to c

}func main()

c := make(chan int)

go sum(s[:len(s)/2], c)

go sum(s[len(s)/2:], c)

x, y := <-c, <-c // receive from c

fmt.println(x, y, x+y)

}

Go併發控制 channel

雖然上次提過的sync控制併發很簡單,但是他有一定的侷限性,他也只能控制能過讓所有的goroutine在程式結束時完成,並不能干涉各個goroutine,下面我們介紹一種更好的方式,就是利用通道 首先先說用channel控制併發在程式結束之前完成 func main ch sum fmt.print...

go語言 channel特點

通道擁有阻塞機制 無緩衝區 有緩衝區同理。接收端在傳送端資料傳送完成之前 通道為nil 處於阻塞狀態 傳送端在接收端資料拿走完成之前 通道為滿 處於阻塞態 1.struct 型別不佔空間,作為通道的一種訊號方式 2.chan型別為引用型別,故需要進行初始化,申請空間,在通道使用結束後close 關閉...

go 通道 go語言通道channel

通過使用通道,在多個goroutine傳送和接受共享的資料,達到資料同步的目的。通道,他有點像在兩個routine之間架設的管道,乙個goroutine可以往這個管道裡塞資料,另外乙個可以從這個管道裡取資料,有點類似於我們說的佇列。宣告乙個通道很簡單,我們使用chan關鍵字即可,除此之外,還要指定通...