Go 語言入門 1-管道的特性及實現原理

2022-09-01 15:01:22

入坑 go 也快一年了,從今天開始會定期分享一下 Go 語言學習過程中的一些基礎知識。

 

go 語言中的管道, 主要是用於協程之間的通訊, 比 UNIX 的管道更加輕量和易用。

 

我們先看一下管道的資料結構:

 

type hchan struct {  gcount   uint  // 環形佇列剩餘元素個數  dataqsiz uint // 環形佇列長度  buf      unsafe.Pointer // 環形佇列指標  elemsize uint16  // 每個元素大小  closed   uint32  // 標識關閉狀態  elemtype *_type  // 元素型別  sendx    uint   // 下一個元素寫入時的下標  recvx    uint   // 下一個元素讀取時的下標  recvq    waitq  //  等待讀訊息的佇列  sendq    waitq  // 等待寫訊息的佇列  lock     mutex  // 互斥鎖, 保障管道無法並行讀寫}

原始碼連結:

https://github.com/golang/go/blob/0d0193409492b96881be6407ad50123e3557fdfb/src/runtime/chan.go#L33


通過上述資料結構, 我們可以理解管道是由三部分組成的:

環形佇列

讀寫等待佇列

佇列元素基本資訊

 

從管道讀取資料時, 如果管道緩衝區為空或者沒有緩衝區, 那麼當前協程就會阻塞, 然後放入 recvq 佇列中。

 

往管道寫入資料時, 如果管道緩衝區為空或者緩衝區滿了, 那麼當前協程就會阻塞, 然後放入 sendq 佇列中。

 

讀阻塞的協程會被新來的寫資料的協程喚醒。

寫阻塞的協程會被新來的讀資料的協程喚醒。

 

同時上述資料結構中, 我們可以看到一個管道中只能傳遞一種元素型別。 如果想資料型別動態化, 可以傳遞 interface。

 

管道的操作:

 

初始化有兩種方式:

 

變數宣告:

var ch chan int  // 宣告一個新的管道

使用 make:

ch1 := make(chan string)  // 無緩衝管道ch1 := make(chan string 3)  // 有緩衝管道

 

管道的讀寫是通過操作符: 「<-」控制的,管道在左邊表示把右側資料寫入到管道中, 管道在右邊表示讀取管道資料賦值給左側變數。

 

ch1 := make(chan string)  // 初始化ch1 <- "gjl";  // 把 gjl 字串寫入到管道中c := <- ch1;  // 讀取管道資料並交給 c 變數fmt.Println(c) // 輸出

 

 

同時也可以通過操作符來限制管道的讀寫許可權。

 

舉個栗子