golang 通道channel 基礎
宣告一個通常的基本語法:channel := make(chan int,0)
當容量為0時,我們可以稱通道為非緩衝通道,當容量大於0時,我們稱為緩衝通道;
一個通道相當於一個先進先出(FIFO)的佇列。也就是說,通道中的各個元素都是嚴格地按照發送的順序排列的,先被髮送通道的元素值一定會先被接受。元素值的傳送和接受都需要用到操作符<-。我們也可以叫它接受操作符。
問:對通道的傳送和接受操作都有哪些基本特性?
答: 1.對於同一個通道,傳送操作之間是互斥的,接受操作之間也是互斥的。
2.傳送操作和接受操作中對元素值的處理都是不可分割的。
3.傳送操作在完全完成之前都會被阻塞。接受操作也是如此。
第一個特性:在同一時刻,Go語言的執行時系統只會執行對同一個通道的任意個傳送操作中的一個。
直到這個元素被完全複製進該通道之後,其針對該通道的傳送操作才可能被執行。
類似的,在同一時刻,執行時系統也只會執行,對同一通道的任意個接受操作中的某一個。
直到這個元素完全被移出該通道之後,其他針對該通道的接受操作才可能被執行。即使這些操作是併發執行的也是如此。
另外,對於通道中的同一個元素來說,傳送操作和接受操作之間也是互斥的。例如:雖然會出現,正在被複制進通道但還未複製完成的元素值,但是這是它絕不會被想接受它的一方看到和取走。
細節:元素值從外界進入通道是會被複制。更具體地說,進入通道的並不是接受操作符右邊的那個元素值,而是它的副本。
第二個特性:傳送操作要麼還沒複製元素值,要麼以及複製完成,絕不會出現複製一部分的情況。這個操作是原子性的。
這既是為了保證通道中元素值的完整性,也是為了保證通道操作的唯一性。對於通道中的同一個元素值來說,它只可能是某一個傳送操作放入的,同時也只可能被某一個接受操作取出。
第三個特性:一般情況下,傳送操作包括了"複製元素值" 和"放置副本到通道內部" 這兩個步驟。
在這兩個步驟完成前,發起這個操作的那句程式碼及grountine會一直阻塞。
另外,接受操作也包括了"複製通道內的元素" 和"放置副本到接收方" ,"刪除原值" 這三個步驟。
在這些步驟完全完成前,發起該操作的程式碼及grountine會一直阻塞。
如此阻塞程式碼其實就是為了實現操作的互斥和元素值的完整。
問題:傳送操作和接受操作在什麼時候可能被長時間的阻塞?
答:對於緩衝通道來說。如果通道已滿,那麼對它的所有傳送操作都會被阻塞,直到通道內有元素值被接受走。
這是,通道會優先通知最早因此而等待的、那個傳送操作所在的goroutine ,因為傳送操作被阻塞後,它們所在的goroutine會順序地進入通道內部的傳送等待佇列;
接受等待情況也是如此,同樣也有接受等待佇列。
對於非緩衝通道,無論是傳送操作還是接受操作,一開始執行就會被阻塞,直到配對的操作開始執行。
在大多數情況下,緩衝通道都會作為收發雙方的中介軟體。元素值會先從傳送方複製到緩衝通道,之後再有緩衝通道複製到接收方。但是,當傳送操作正在執行的時候發現空的通道中,正好有等待的接受操作,那麼它會直接把元素值複製給接收方。
對於值為nil的通道,不論它的具體型別是什麼,對它的傳送操作和接受操作都會永久處於阻塞狀態。
問題:傳送操作和接受操作在什麼時候引發panic?
1.對一個已關閉的channel 進行傳送操作,會引發panic
2.關閉一個已經關閉了的channel,會引發panic
注意:接受操作是可以感知到通道關閉的,並能夠安全退出。當我們把接受表示式的結構同時賦值給兩個變數時,第二個值為false代表通道已經關閉,並且沒有元素可取。
如果通道關閉時,裡面還有元素未被取出,那麼接受表示式的第二個結果一定是true。因此,通過表示式的第二個結果,判斷通道是否關閉具有延時性。
注:通道長度代表通道當前包含的元素個數。