<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之旅 廣告
                從不同的并發執行的協程中獲取值可以通過關鍵字`select`來完成,它和`switch`控制語句非常相似(章節5.3)也被稱作通信開關;它的行為像是“你準備好了嗎”的輪詢機制;`select`監聽進入通道的數據,也可以是用通道發送值的時候。 ~~~ select { case u:= <- ch1: ... case v:= <- ch2: ... ... default: // no value ready to be received ... } ~~~ `default`?語句是可選的;fallthrough 行為,和普通的 switch 相似,是不允許的。在任何一個 case 中執行?`break`?或者?`return`,select 就結束了。 `select`?做的就是:選擇處理列出的多個通信情況中的一個。 * 如果都阻塞了,會等待直到其中一個可以處理 * 如果多個可以處理,隨機選擇一個 * 如果沒有通道操作可以處理并且寫了?`default`?語句,它就會執行:`default`?永遠是可運行的(這就是準備好了,可以執行)。 在?`select`?中使用發送操作并且有?`default`可以確保發送不被阻塞!如果沒有 case,select 就會一直阻塞。 `select`?語句實現了一種監聽模式,通常用在(無限)循環中;在某種情況下,通過?`break`?語句使循環退出。 在程序?[goroutine_select.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_14/goroutine_select.go)?中有 2 個通道?`ch1`?和?`ch2`,三個協程?`pump1()`、`pump2()`?和?`suck()`。這是一個典型的生產者消費者模式。在無限循環中,`ch1`?和?`ch2`?通過?`pump1()`?和?`pump2()`?填充整數;`suck()`?也是在無限循環中輪詢輸入的,通過`select`?語句獲取?`ch1`?和?`ch2`?的整數并輸出。選擇哪一個 case 取決于哪一個通道收到了信息。程序在 main 執行 1 秒后結束。 示例 14.10-[goroutine_select.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_14/goroutine_select.go): ~~~ package main import ( "fmt" "time" ) func main() { ch1 := make(chan int) ch2 := make(chan int) go pump1(ch1) go pump2(ch2) go suck(ch1, ch2) time.Sleep(1e9) } func pump1(ch chan int) { for i := 0; ; i++ { ch <- i * 2 } } func pump2(ch chan int) { for i := 0; ; i++ { ch <- i + 5 } } func suck(ch1, ch2 chan int) { for { select { case v := <-ch1: fmt.Printf("Received on channel 1: %d\n", v) case v := <-ch2: fmt.Printf("Received on channel 2: %d\n", v) } } } ~~~ 輸出: ~~~ Received on channel 2: 5 Received on channel 2: 6 Received on channel 1: 0 Received on channel 2: 7 Received on channel 2: 8 Received on channel 2: 9 Received on channel 2: 10 Received on channel 1: 2 Received on channel 2: 11 ... Received on channel 2: 47404 Received on channel 1: 94346 Received on channel 1: 94348 ~~~ 一秒內的輸出非常驚人,如果我們給它計數(goroutine_select2.go),得到了 90000 個左右的數字。 ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/14.4.md#練習)練習: 練習 14.7: * a)在練習 5.4 的 for_loop.go 中,有一個常見的 for 循環打印數字。在函數?`tel`?中實現一個 for 循環,用協程開始這個函數并在其中給通道發送數字。`main()`?線程從通道中獲取并打印。不要使用?`time.Sleep()`?來同步:[goroutine_panic.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/goroutine_panic.go) * b)也許你的方案有效,可能會引發運行時的 panic:`throw:all goroutines are asleep-deadlock!`?為什么會這樣?你如何解決這個問題?[goroutine_close.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/goroutine_close.go) * c)解決 a)的另外一種方式:使用一個額外的通道傳遞給協程,然后在結束的時候隨便放點什么進去。`main()`?線程檢查是否有數據發送給了這個通道,如果有就停止:[goroutine_select.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/goroutine_select.go) 練習 14.8: 從示例 6.10 的斐波那契程序開始,制定解決方案,使斐波那契周期計算獨立到協程中,并可以把結果發送給通道。 結束的時候關閉通道。`main()`?函數讀取通道并打印結果:[goFibonacci.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/gofibonacci.go) 使用練習 6.9 中的算法寫一個更短的?[gofibonacci2.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/gofibonacci2.go) 使用?`select`?語句來寫,并讓通道退出([gofibonacci_select.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/gofibonacci_select.go)) 注意:當給結果計時并和 6.10 對比時,我們發現使用通道通信的性能開銷有輕微削減;這個例子中的算法使用協程并非性能最好的選擇;但是?[gofibonacci3](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/gofibonacci3.go)?方案使用了 2 個協程帶來了 3 倍的提速。 練習 14.9: 做一個隨機位生成器,程序可以提供無限的隨機 0 或者 1 的序列:[random_bitgen.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/random_bitgen.go) 練習 14.10:[polar_to_cartesian.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/polar_to_cartesian.go) (這是一種綜合練習,使用到第 4、9、11 章和本章的內容。)寫一個可交互的控制臺程序,要求用戶輸入二位平面極坐標上的點(半徑和角度(度))。計算對應的笛卡爾坐標系的點的 x 和 y 并輸出。使用極坐標和笛卡爾坐標的結構體。 使用通道和協程: * `channel1`?用來接收極坐標 * `channel2`?用來接收笛卡爾坐標 轉換過程需要在協程中進行,從 channel1 中讀取然后發送到 channel2。實際上做這種計算不提倡使用協程和通道,但是如果運算量很大很耗時,這種方案設計就非常合適了。 練習 14.11:?[concurrent_pi.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/concurrent_pi.go)?/?[concurrent_pi2.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_14/concurrent_pi2.go) 使用以下序列在協程中計算 pi:開啟一個協程來計算公式中的每一項并將結果放入通道,`main()`?函數收集并累加結果,打印出 pi 的近似值。 [![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/images/14.4_piseries.png?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/images/14.4_piseries.png?raw=true) 計算執行時間(參見第?[6.11](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/6.11.md)?節) 再次聲明這只是為了一邊練習協程的概念一邊找點樂子。 如果你需要的話可使用?`math.pi`?中的 Pi;而且不使用協程會運算的更快。一個急速版本:使用?`GOMAXPROCS`,開啟和`GOMAXPROCS`?同樣多個協程。 習慣用法:后臺服務模式 服務通常是是用后臺協程中的無限循環實現的,在循環中使用?`select`?獲取并處理通道中的數據: ~~~ // Backend goroutine. func backend() { for { select { case cmd := <-ch1: // Handle ... case cmd := <-ch2: ... case cmd := <-chStop: // stop server } } } ~~~ 在程序的其他地方給通道?`ch1`,`ch2`?發送數據,比如:通道?`stop`?用來清理結束服務程序。 另一種方式(但是不太靈活)就是(客戶端)在?`chRequest`?上提交請求,后臺協程循環這個通道,使用?`switch`?根據請求的行為來分別處理: ~~~ func backend() { for req := range chRequest { switch req.Subjext() { case A1: // Handle case ... case A2: // Handle case ... default: // Handle illegal request .. // ... } } } ~~~
                  <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>

                              哎呀哎呀视频在线观看