日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

channelinactive触发后不关闭channel_go那些事儿|channel使用及其实现原理

發布時間:2023/12/10 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 channelinactive触发后不关闭channel_go那些事儿|channel使用及其实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄?

  • channel背景

  • channel基本用法

  • channel應用場景

  • channel實現原理

    • channel數據結構

    • channel實現方式

  • channel注意事項

  • 閑聊

  • 歡迎加入我的公眾號【邁莫coding】 一起pk大廠

1channel背景

channel是Go的核心類型,是Go語言內置的類型,你無需引包,就能使用它。你可以把它看作一個管道,在Go語言中流傳著一句話,"執行業務處理的goroutine不要通過共享內存通信,要通過channel管道進行共享數據"

channel和Go的另一種特性goroutine一起為并發編程提供了優雅的,便利的方案,來應對并發場景。

2channel基本用法

channel的基本用法非常簡單,它提供了三種類型,分別為只能接收只能發送既能接收也能發送這三種類型。因此它的語法為:

chanstruct{} chan chan string // 既能接收也能發送

我們把既能發送也能接收的chan被稱為雙向chan,把只能接收或者只能發送的chan稱為單向chan。其中,"這個箭頭總是射向左邊的,元素類型總在最右邊。如果箭頭指向 chan,就表示可以往 chan 中塞數據;如果箭頭遠離 chan,就表示 chan 會往外吐數據。

通過make關鍵字,我們可以初始化一個chan,未初始化的chan的零值為nil。你可以設置他的容量,第二個參數為緩沖池的容量大小,也可以理解為即使chan未消費完,也可以存儲數據。

make(chan int, 8)?

如果chan中還有數據,那么從這個chan中接收數據就不會阻塞,如果chan中數據未達到隊列容量,那么向該chan中存儲數據也不會阻塞,反之會阻塞。

還有一個知識點要記住:nil 是 chan 的零值,是一種特殊的 chan,對值是 nil 的 chan 的發送接收調用者總是會阻塞。

接下來,我們用代碼來學習一下chan的三種類型

  • 只能接收數據的chan

代碼示例

package main import "fmt"// a 表示只能接收數據的chanfunc goChanA(a chan int) { b := fmt.Println("只能接收數據的channal[a]接收到的數據值為", b)}func main() { ch := make(chan int, 2) go goChanA(ch) // 往ch中寫入數據值 ch 2 time.Sleep(time.Second)}

結果

只能接收數據的channal[a]接收到的數據值為 2?
  • 只能發送數據的chan

代碼示例

package main import "fmtfunc main() { ch := make(chan ch }

往 chan 中發送一個數據使用“ch

這里的 ch 是 chan int 類型或者是 chan

3channel應用場景

  • 數據交流:當作并發的 buffer 或者 queue,解決生產者 - 消費者問題。多個 goroutine 可以并發當作生產者(Producer)和消費者(Consumer)。

  • 數據傳遞:一個goroutine將數據交給另一個goroutine,相當于把數據的擁有權托付出去。

  • 信號通知:一個goroutine可以將信號(closing,closed,data ready等)傳遞給另一個或者另一組goroutine。

  • 任務編排:可以讓一組goroutine按照一定的順序并發或者串行的執行,這就是編排功能。

  • 鎖機制:利用channel實現互斥機制。

4channel實現原理

channel數據結構

channel一個類型管道,通過它可以在goroutine之間發送消息和接收消息。它是golang在語言層面提供的goroutine間的通信方式。

眾所周知,Go依賴于稱為CSP(Communicating Sequential Processes)的并發模型,通過 Channel實現這種同步模式。?

channel結構體

//path:src/runtime/chan.gotype hchan struct { qcount uint // 當前隊列列中剩余元素個數 dataqsiz uint // 環形隊列長度,即可以存放的元素個數 buf unsafe.Pointer // 環形隊列列指針 elemsize uint16 // 每個元素的?? closed uint32 // 標識關閉狀態 elemtype *_type // 元素類型 sendx uint // 隊列下標,指示元素寫?入時存放到隊列列中的位置 x recvx uint // 隊列下標,指示元素從隊列列的該位置讀出 recvq waitq // 等待讀消息的goroutine隊列 sendq waitq // 等待寫消息的goroutine隊列 lock mutex // 互斥鎖,chan不允許并發讀寫}

從數據結構可以看出channel由隊列、類型信息、goroutine等待隊列組成。? ? ? ?

channel實現方式

chan內部實現了一個緩沖隊列作為緩沖區,隊列的長度是創建chan時指定的。

下圖展示了可緩存6個元素的channel示意圖:

  • dataqsiz:指向隊列的長度為6,即可緩存6個元素

  • buf:指向隊列的內存,隊列中還剩余兩個元素

  • qcount:當前隊列中剩余的元素個數

  • sendx:指后續寫入元素的位置

  • recvx:指從該位置讀取數據

等待隊列

從channel中讀數據,如果channel緩沖區為空或者沒有緩沖區,當前goroutine會被阻塞;向channel中寫數據,如果channel緩沖區已滿或者沒有緩沖區,當前goroutine會被阻塞。

被阻塞的goroutine將會被掛在channel的等待隊列中:

  • 因讀阻塞的goroutine會被向channel寫入數據的goroutine喚醒

  • 因寫阻塞的goroutine會被從channel讀數據的goroutine喚醒

下面展示了一個沒有緩沖區的channel,有幾個goroutine阻塞等待數據:

注意,一般情況下recvq和sendq至少有一個為空。只有一個例外,那就是同一個goroutine使用select語句向channel一邊寫數據一邊讀數據。

向channel寫數據

  • 流程圖:

  • 詳細過程

    • 如果recvq隊列不為空,說明緩沖區沒有數據或者沒有緩沖區,此時直接從recvq等待隊列中取出一個G,并把數據寫入,最后把該G喚醒,結束發送過程;

    • 如果緩沖區有空余位置,則把數據寫入緩沖區中,結束發送過程;

    • 如果緩沖區沒有空余位置,則把數據寫入G,將當前G寫入sendq隊列,進入休眠,等待被讀goroutine喚醒;

從channel讀數據

  • 流程圖

  • 詳細過程

    • 如果等待發送隊列sendq不為空,且沒有緩沖區,直接從sendq隊列中取出G,把G中數據讀出,最后把G喚醒,結束讀取過程;

    • 如果等待發送隊列sendq不為空,說明緩沖區已滿,從緩沖隊列中首部讀取數據,從sendq等待發送隊列中取出G,把G中的數據寫入緩沖區尾部,結束讀取過程;

    • 如果緩沖區中有數據,則從緩沖區取出數據,結束讀取過程;

5channel注意事項
  • 向已經關閉的channel中寫入數據會發生Panic

  • 關閉已經關閉的channel會發生Panic

  • 關閉值為nil的channel會發生Panic

6閑聊

  • 讀完文章,自己是不是和channel管道的cp率又提高了

  • 我是邁莫,歡迎大家和我交流

原創不易,覺得文章寫得不錯的小伙伴,點個贊? 鼓勵一下吧~

7歡迎加入我的公眾號【邁莫coding】 一起pk大廠

  • 邁莫coding歡迎客官的到來

總結

以上是生活随笔為你收集整理的channelinactive触发后不关闭channel_go那些事儿|channel使用及其实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。