<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                `src/runtime/chan.go:hchan`定義了channel的數據結構: ~~~ type hchan struct { qcount uint // 當前隊列中剩余元素個數 dataqsiz uint // 環形隊列長度,即可以存放的元素個數 buf unsafe.Pointer // 環形隊列指針 elemsize uint16 // 每個元素的大小 closed uint32 // 標識關閉狀態 elemtype *_type // 元素類型 sendx uint // 隊列下標,指示元素寫入時存放到隊列中的位置 recvx uint // 隊列下標,指示元素從隊列的該位置讀出 recvq waitq // 等待讀消息的goroutine隊列 sendq waitq // 等待寫消息的goroutine隊列 lock mutex // 互斥鎖,chan不允許并發讀寫 } ~~~ ### 環形隊列 chan內部實現了一個環形隊列作為其緩沖區,隊列的長度是創建chan時指定的。 下圖展示了一個可緩存6個元素的channel示意圖: ![](https://img.kancloud.cn/4f/d7/4fd7f81a523c48f3de21c1ce1dbf237e_503x267.png) * dataqsiz指示了隊列長度為6,即可緩存6個元素; * buf指向隊列的內存,隊列中還剩余兩個元素; * qcount表示隊列中還有兩個元素; * sendx指示后續寫入的數據存儲的位置,取值\[0, 6); * recvx指示從該位置讀取數據, 取值\[0, 6); ### 等待隊列 從channel讀數據,如果channel緩沖區為空或者沒有緩沖區,當前goroutine會被阻塞。 向channel寫數據,如果channel緩沖區已滿或者沒有緩沖區,當前goroutine會被阻塞。 被阻塞的goroutine將會掛在channel的等待隊列中: * 因讀阻塞的goroutine會被向channel寫入數據的goroutine喚醒; * 因寫阻塞的goroutine會被從channel讀數據的goroutine喚醒; 下圖展示了一個沒有緩沖區的channel,有幾個goroutine阻塞等待讀數據: ![](https://img.kancloud.cn/db/ed/dbed088680c6fea879fe5a6ba7a1a382_417x309.png) 注意,一般情況下recvq和sendq至少有一個為空。只有一個例外,那就是同一個goroutine使用select語句向channel一邊寫數據,一邊讀數據 ### channel寫數據 向一個channel中寫數據簡單過程如下: 1. 如果等待接收隊列recvq不為空,說明緩沖區中沒有數據或者沒有緩沖區,此時直接從recvq取出G,并把數據寫入,最后把該G喚醒,結束發送過程; 2. 如果緩沖區中有空余位置,將數據寫入緩沖區,結束發送過程; 3. 如果緩沖區中沒有空余位置,將待發送數據寫入G,將當前G加入sendq,進入睡眠,等待被讀goroutine喚醒; 簡單流程圖如下: ![](https://img.kancloud.cn/53/bc/53bc89a2b13bde4ad44b819c8d8a0f96_488x569.png) ### channel讀數據 從一個channel讀數據簡單過程如下: 1. 如果等待發送隊列sendq不為空,且沒有緩沖區,直接從sendq中取出G,把G中數據讀出,最后把G喚醒,結束讀取過程; 2. 如果等待發送隊列sendq不為空,此時說明緩沖區已滿,從緩沖區中首部讀出數據,把G中數據寫入緩沖區尾部,把G喚醒,結束讀取過程; 3. 如果緩沖區中有數據,則從緩沖區取出數據,結束讀取過程; 4. 將當前goroutine加入recvq,進入睡眠,等待被寫goroutine喚醒; 簡單流程圖如下: ![](https://img.kancloud.cn/cf/a0/cfa0af1fee25a06e2f2422ad560d3c76_608x744.png) ### 關閉channel 關閉channel時會把recvq中的G全部喚醒,本該寫入G的數據位置為nil。把sendq中的G全部喚醒,但這些G會panic。 除此之外,panic出現的常見場景還有: 1. 關閉值為nil的channel 2. 關閉已經被關閉的channel 3. 向已經關閉的channel寫數據
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看