<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                Golang 的 select 機制可以理解為是在語言層面實現了和select, poll, epoll 相似的功能:監聽多個描述符的讀/寫等事件,一旦某個描述符就緒(一般是讀或者寫事件發生了),就能夠將發生的事件通知給關心的應用程序去處理該事件。 golang 的 select 機制是,監聽多個channel,每一個 case 是一個事件,可以是讀事件也可以是寫事件,隨機選擇一個執行,可以設置default. 它的作用是:當監聽的多個事件都阻塞住會執行default的邏輯。 select的源碼在 (runtime/select.go)\[[https://github.com/golang/go/blob/master/src/runtime/select.go](https://github.com/golang/go/blob/master/src/runtime/select.go)\] ,看的時候建議是重點關注 pollorder 和 lockorder. * pollorder保存的是scase的序號,亂序是為了之后執行時的隨機性。 * lockorder保存了所有case中channel的地址,這里按照地址大小堆排了一下lockorder對應的這片連續內存。對chan排序是為了去重,保證之后對所有channel上鎖時不會重復上鎖。 goroutine作為Golang并發的核心,我們不僅要關注它們的創建和管理,當然還要關注如何合理的退出這些協程,不(合理)退出不然可能會造成阻塞、panic、程序行為異常、數據結果不正確等問題。goroutine在退出方面,不像線程和進程,不能通過某種手段強制關閉它們,只能等待goroutine主動退出。 goroutine的優雅退出方法有三種: 1. 使用for-range退出 for-range是使用頻率很高的結構,常用它來遍歷數據,range能夠感知channel的關閉,當channel被發送數據的協程關閉時,range就會結束,接著退出for循環。 它在并發中的使用場景是:當協程只從1個channel讀取數據,然后進行處理,處理后協程退出。下面這個示例程序,當in通道被關閉時,協程可自動退出。 ~~~go go func(in <-chan int) { // Using for-range to exit goroutine // range has the ability to detect the close/end of a channel for x := range in { fmt.Printf("Process %d\n", x) } }(in) ~~~ 2. 使用select case ,ok退出 for-select也是使用頻率很高的結構,select提供了多路復用的能力,所以for-select可以讓函數具有持續多路處理多個channel的能力。但select沒有感知channel的關閉,這引出了2個問題: 繼續在關閉的通道上讀,會讀到通道傳輸數據類型的零值,如果是指針類型,讀到nil,繼續處理還會產生nil。 繼續在關閉的通道上寫,將會panic。 問題2可以這樣解決,通道只由發送方關閉,接收方不可關閉,即某個寫通道只由使用該select的協程關閉,select中就不存在繼續在關閉的通道上寫數據的問題。 問題1可以使用,ok來檢測通道的關閉,使用情況有2種。 第一種:如果某個通道關閉后,需要退出協程,直接return即可。示例代碼中,該協程需要從in通道讀數據,還需要定時打印已經處理的數量,有2件事要做,所有不能使用for-range,需要使用for-select,當in關閉時,ok=false,我們直接返回。 ~~~go go func() { // in for-select using ok to exit goroutine for { select { case x, ok := <-in: if !ok { return } fmt.Printf("Process %d\n", x) processedCnt++ case <-t.C: fmt.Printf("Working, processedCnt = %d\n", processedCnt) } } }() ~~~ 第二種:如果某個通道關閉了,不再處理該通道,而是繼續處理其他case,退出是等待所有的可讀通道關閉。我們需要使用select的一個特征:select不會在nil的通道上進行等待。這種情況,把只讀通道設置為nil即可解決。 ~~~go go func() { // in for-select using ok to exit goroutine for { select { case x, ok := <-in1: if !ok { in1 = nil } // Process case y, ok := <-in2: if !ok { in2 = nil } // Process case <-t.C: fmt.Printf("Working, processedCnt = %d\n", processedCnt) } // If both in channel are closed, goroutine exit if in1 == nil && in2 == nil { return } } }() ~~~ 3. 使用退出通道退出 使用,ok來退出使用for-select協程,解決是當讀入數據的通道關閉時,沒數據讀時程序的正常結束。想想下面這2種場景,,ok還能適用嗎? 接收的協程要退出了,如果它直接退出,不告知發送協程,發送協程將阻塞。啟動了一個工作協程處理數據,如何通知它退出? 使用一個專門的通道,發送退出的信號,可以解決這類問題。以第2個場景為例,協程入參包含一個停止通道stopCh,當stopCh被關閉,case <-stopCh會執行,直接返回即可。 當我啟動了100個worker時,只要main()執行關閉stopCh,每一個worker都會都到信號,進而關閉。如果main()向stopCh發送100個數據,這種就低效了。 ~~~go func worker(stopCh <-chan struct{}) { go func() { defer fmt.Println("worker exit") // Using stop channel explicit exit for { select { case <-stopCh: fmt.Println("Recv stop signal") return case <-t.C: fmt.Println("Working .") } } }() return } ~~~ 通過channel控制子goroutine的方法可以總結為:循環監聽一個channel,一般來說是for循環里放一個select監聽channel以達到通知子goroutine的效果。再借助Waitgroup,主進程可以等待所有協程優雅退出后再結束自己的運行,這就通過channel實現了優雅控制goroutine并發的開始和結束。 因此在退出協程的時候需要注意: * 發送協程主動關閉通道,接收協程不關閉通道。使用技巧:把接收方的通道入參聲明為只讀,如果接收協程關閉只讀協程,編譯時就會報錯。 * 協程處理1個通道,并且是讀時,協程優先使用for-range,因為range可以關閉通道的關閉自動退出協程。 * ok可以處理多個讀通道關閉,需要關閉當前使用for-select的協程。 * 顯式關閉通道stopCh可以處理主動通知協程退出的場景。
                  <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>

                              哎呀哎呀视频在线观看