徹底搞懂 channel 原理 -二-
上一篇文章主要介紹channel
運行時是通過hchan
表示的,也簡單說明了hchan
各個字段的含義。
我們提到,對channel
的操作,本質上就是對hchan
裏字段的操作。因爲在操作的過程中使用了互斥鎖,所以保證了channel
的併發安全。
這篇文章主要通過現實生活的一些例子來說明channel
的一些原理,當然還是不會涉及過多源碼。
無緩衝
我們都知道,channel
分爲無緩衝和緩衝。這兩者最大的區別是什麼?
我們用一個現實生活的快遞例子來說明。
上面場景是快遞員在等小庫,當然反過來小庫也可能在等快遞員。
如果沒有快遞櫃,快遞員在送快遞的過程中,如果家裏沒人,他就得在那等着,等着有人來簽收快遞,他才送貨結束。
客戶在快遞員到來之前,他也不能離開家,不然快遞來了沒人收,所以他也得等到快遞員上門,簽字收了快遞,他纔算收貨結束。
當然,客戶不止有這家快遞,如果快遞員 A 在等的時候又來一個快遞員 B 給他送貨。這個快遞員 B 不僅得等着,還得排隊。等到客戶到家後,肯定是先簽收 A 的快遞,然後再簽收 B 的快遞。
對應到無緩衝channel
,
發送數據的時候,如果沒有對應的接收者ready
,那麼發送者就進入到等待發送隊列中,等待有對應的接收者喚醒它。
接收數據的時候,如果沒有對應的發送者ready
,那麼接收者就進入到等待接收隊列中,等待有對應的發送者喚醒它。
還記得上一篇文章我們介紹過hchan
的結構嗎。
其中recvq
表示等待接收消息的隊列,sendq
表示等待發送消息的隊列。
我們來看waitq
。
本質上waitq
就是一個鏈表,更確切的說是一個雙向循環的鏈表。其中waitq
記錄了鏈表的頭尾,sudog
記錄了當前等待者的上一個等待者 (prev
) 和下一個等待者 (next
)。
這就好像小庫在簽收完 A 的快遞後喊,下一個是誰啊?
A 會說: 我的下一個是 B。
B 會說: 是我。我記得我上一個是 A,目前我沒有下一個,所以我是最後一個。
緩衝
看完了無緩衝隊列,我們再來看緩衝隊列。還是用上面的故事,
只要快遞櫃有空閒櫃子,快遞員就可以直接把快遞放到櫃子裏,讓客戶自己去櫃子拿。如果發送沒有空閒的櫃子,那就只能等,等到別人告訴我有空閒櫃子,我再把快遞放到空出來的櫃子裏。
對應到緩衝channel
,上面的快遞櫃,就是緩衝channel
中存儲數據的buffer
。
對於發送者來說:只要緩衝區未滿,發送者就可以繼續發送數據存放在緩衝區。一旦緩衝區滿了,發送者就只能進入到等待發送隊列中,等待有對應的接收者喚醒它,然後它再把數據放入到剛剛被取走數據的位置。
對於接收者來說:只要緩衝區不爲空,接收者就可以繼續接收數據。一旦緩衝區空了,那麼接收者就只能進入到等待接收隊列中,等待有對應的發送者喚醒它。
上面還有什麼問題嗎?還真有。
我們取快遞的時候,你一定會按照快遞放入到快遞櫃的先後順序取快遞嗎?咋麼可能。
但是在channel
中,是會保證消息的先進先出 (FIFO) 關係的。至於咋麼保證的,我們終結篇解析代碼細節的時候再說。
總結
這篇文章主要通過一個快遞的例子來介紹channel
操作的原理。下一篇我們介紹channel
針對上述處理的細節邏輯。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/xWPxuk3WePB4fgz749yfyA