Go 知识点(03)— 非缓冲 channel 的长度始终为 0
我們先看下面代碼輸出通道的長度是多少?
func main() {ch := make(chan string)go func() {ch <- "hello"close(ch)}()time.Sleep(5 * time.Second)fmt.Println("ch length is ", len(ch))<-ch
}
是 1 嗎? 答案是: 0, 為什么呢?
我們來分析下,首先在主協程中創建了一個通道,然后在子協程中往這個通道中發送內容,發送完畢后關閉通道,然后在主協程中等待 5s, 等待的目的是讓子協程能夠運行起來,隨后我們打印通道的長度。
我們知道對于非緩沖通道而言,發送方和接收方必須同時準備好,這樣數據才能發送過去,而在上面代碼中我們先打印通道的長度,然后主協程作為接收方才會從通道中取消息內容,所以我們打印通道的時候由于接收方還沒有準備接收,從而導致發送方一直處于阻塞狀態,此時消息是沒有進入到通道的,所以此時的通道長度為 0 。
非緩沖通道并不需要內存空間來存儲發送的消息內容,它在發送方和接受方都準備好時,直接將發送方的消息內容拷貝到接收方。
緩沖通道在容量夠的時候,寫入操作并不會阻塞,是否阻塞強依賴于讀取操作,發送方發送數據后直接返回,這樣就決定了緩沖通道需要一塊存儲空間來真正存儲要發送的消息內容。
在多核 CPU 下的 Go 多協程環境,必然會出現多個協程同時并行的對同一個 channel 進行讀取操作的情況,這樣就帶來了資源并發訪問的問題。
對于非緩沖通道,發送方與接收方必須是一對一、點對點的操作。如果有多個協程同時對某一個非緩沖 channel 進行操作,那么就會發生有部分讀/寫操作不能匹配到相應的寫/讀操作,必然會導致死鎖。
對于緩沖通道,由于 Go 采用對通道接收的鎖機制,即在接收方在取通道內容時,先用鎖把通道鎖住,然后取數據,取完數據之后再釋放鎖,這樣就保證了多個協程之間是順序執行的,不會發生多個協程獲取通道里的同一個數據的問題,在某一個協程進行接收操作的時候,其他協程只能阻塞在那里,等待上一個協程釋放鎖,這樣就保證了通道數據的并發安全性。
同樣發送方也遵循這樣的鎖機制,即保證同一時刻只有一個協程來操作通道。
總結
以上是生活随笔為你收集整理的Go 知识点(03)— 非缓冲 channel 的长度始终为 0的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022-2028年中国PPS树脂产业研
- 下一篇: Go 知识点(04)— 结构体字段转 j