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

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                > channel管道是Go語言推薦的協程之間的通信機制 > channel是一個數據類型,主要用來解決go程的同步問題以及協程之間數據共享(數據傳遞)的問題 [TOC] ### 創建channel > 語法 ``` channel := make(chan 數據類型) ``` > 例子 ``` // 創建int類型的channel channel := make(chan int) ``` ### 讀取channel的數據 > 語法 ~~~ // 從channel讀取數據,保存至變量v v := <-channel // 從channel讀取數據,數據直接丟棄 <-channel ~~~ > 如果channel沒有數據,讀取channel會阻塞,同時觸發寫channel攜程 ~~~ package main import ( "fmt" "strconv" "time" ) func collectPersons(n int, name string, c chan string) { for i := 0; i < n; i++ { // 往channel寫數據 c <- name + strconv.FormatInt(int64(i), 10) fmt.Println("hello" + strconv.FormatInt(int64(i), 10)) } } func main() { // 定義string類型的channel,緩沖隊列大小是10 channel := make(chan string, 5) // 創建一個協程,往channel里寫數據 go collectPersons(5, "jiaojiao", channel) fmt.Println("___main111___") time.Sleep(1 * time.Second) // 第1句:讀取channel阻塞(因為channel數據為空),同時觸發collectPersons()里的channel寫數據 fmt.Println(<-channel) fmt.Println("___main222___") fmt.Println(<-channel) } ~~~ > 結果 ~~~ ___main111___ hello0 hello1 hello2 hello3 hello4 jiaojiao0 ___main222___ jiaojiao1 ___main333___ jiaojiao2 ~~~ > 如果channel里根本就沒有寫入數據,channel讀取數據時,則會超時報錯,則可以采用`select`來處理超時等待問題 ~~~ package main import ( "fmt" ) func main() { channel := make(chan string, 2) channel <- "haha" fmt.Println(<-channel) // 第2句讀取,因為channel沒有數據,則會報錯,為了防止此類問題,需要用到select fmt.Println(<-channel) } ~~~ ### 往channel寫數據 ``` // 往channel變量c中,寫入int數據100 channel <- 100 ``` ### channel緩沖區 ~~~ // 有緩沖區channel ch := make(chan int, 100) // 無緩沖區channel ch := make(chan int) //等價于make(chan int, 0) ~~~ #### 無緩沖區channel > 無緩沖的通道(unbuffered channel)是指在接收前沒有能力保存任何值的通道 > 這種類型的通道要求`發送channel`和`接收channel`同時準備好,才能完成發送和接收操作,否則都阻塞等待 > 對通道進行`發送`和`接收`是同步的操作行為。其中任意一個操作都無法離開另一個操作單獨存在 ~~~ package main import ( "fmt" "strconv" ) func say(name string, c chan string) { for i := 0; i < 5; i++ { c <- name + strconv.FormatInt(int64(i), 10) fmt.Println("_______hello" + strconv.FormatInt(int64(i), 10)) } } func main() { // 定義一個無緩沖區的channel channel := make(chan string) //channel := make(chan string, 0) go say("jiaojiao", channel) // 由于是無緩沖區channel,每次讀取的時候,都會去觸發寫channel,類似于同步方法 fmt.Println(<-channel) fmt.Println(<-channel) fmt.Println(<-channel) fmt.Println("done") } ~~~ > 結果 > 以下的jiaojiao和hello無所謂誰先執行,因為`無緩沖區的channel`是需要讀取和寫操作同時準備好了后,才會執行,所以print()信息時候,很有可能有先有后 ~~~ _______hello0 jiaojiao0 ---------------------- jiaojiao1 _______hello1 ---------------------- _______hello2 jiaojiao2 ---------------------- done ~~~ #### 有緩沖區channel > 緩沖區,指的是channel中有一個緩沖隊列,只有緩沖區填滿后才會阻塞寫操作 ~~~ package main import ( "fmt" "strconv" ) func say(name string, c chan string) { for i := 0; i < 5; i++ { c <- name + strconv.FormatInt(int64(i), 10) fmt.Println("_______hello" + strconv.FormatInt(int64(i), 10)) } } func main() { // 定義一個channel,用來數據通訊 channel := make(chan string, 5) go say("jiaojiao", channel) // 第一句讀取的時候,讀channel阻塞,并且觸發寫channel,由于channel緩沖區為5,所以寫操作時一次性執行了5次 fmt.Println(<-channel) fmt.Println(<-channel) fmt.Println(<-channel) fmt.Println("done") } ~~~ > 結果 ~~~ _______hello0 _______hello1 _______hello2 _______hello3 _______hello4 jiaojiao0 jiaojiao1 jiaojiao2 done ~~~ ### 單向channel > channel默認是雙向的,但是我們可以顯示的指定他為單向的 ~~~ var writeChannel chan<-int = ch //只能寫,不能讀 var readChannel <-chan int = ch //只能讀,不能寫 ~~~ > 例子 ~~~ package main import ( "fmt" ) func producer(out chan<-int) { for i := 0; i <10; i++ { out <- i*i } close(out) } func consumer(in <-chan int) { for num := range in{ fmt.Println("num = ", num) } } func main() { //創建channel channel := make(chan int) //生產者,只能寫入channel go producer(channel) //消費者,只能讀取消費channel consumer(channel) } ~~~ ### 關閉channel > 只有發送者可以關閉管道,接收者不能關閉管道 ~~~ package main import ( "fmt" ) func main() { //創建channel ch := make(chan int) go func() { for i := 0; i < 5; i++ { ch <- i //寫數據 } //不需要寫數據了,關閉channel close(ch) }() for { //如果ok為true,說明管道沒關閉 if num, ok := <-ch; ok == true { fmt.Println("num = ", num) } else { //管道關閉 break } } } ~~~ ### 遍歷channel > 可以使用for語句循環讀取channel中的數據 ~~~ package main import ( "fmt" "strconv" ) func collectPersons(n int, name string, c chan string) { for i := 0; i < n; i++ { // 返回當前計算結果 c <- name + strconv.FormatInt(int64(i), 10) fmt.Println("_______hello" + strconv.FormatInt(int64(i), 10)) } // 通過close關閉channel close(c) } func main() { // 定義string類型的channel,緩沖隊列大小是3 channel := make(chan string, 3) // 創建一個協程,往channel里寫數據 go collectPersons(3, "jiaojiao", channel) // 通過range關鍵詞,循環遍歷channel // 如果channel沒有數據,就阻塞循環,直到channel中有數據 // 如果channel關閉,則退出循環 for i := range channel { fmt.Println(i) } } ~~~ > 返回結果 ~~~ _______hello0 _______hello1 _______hello2 jiaojiao0 jiaojiao1 jiaojiao2 ~~~ ### select語句 > select語句會阻塞等待多個channel,直到滿足條件后執行(如果滿足多個條件,隨機執行) > select語句中的每個 case 語句里必須是一個 IO 操作 > select本身不帶循環,操作需要外層的for ~~~ package main import "fmt" // select模式,寫入channel (當然也可改為讀取channel,根據自己業務邏輯來) func writeLoop(c, quit chan int) { x := 1 // 開始一個死循環 for { // 通過select等待通道c和quit,看那個有反應,就執行對應的case語句中的代碼 select { case c <- x: // 如果通道c寫入數據成功,執行這里的計算邏輯 x = x + 1 case <-quit: // 如果收到通道quit的數據,就退出函數,結束計算 fmt.Println("quit") return } } } func main() { // 定義一個channel,用來數據通訊 channel := make(chan int) // 定義一個channel,用來傳遞停止通知 quit := make(chan int) // 創建一個協程,用來打印計算結果 go func() { // 打印10個計算結果 for i := 0; i < 10; i++ { // 循環從channel通道中讀取10次數據,每次讀取都觸發channel的select模式 fmt.Println(<-channel) } // 往quit通道中發送數據0,通知writeLoop函數退出,主協程就結束了 quit <- 0 }() // 開啟channel select模式 writeLoop(channel, quit) fmt.Println("done") } ~~~ > 以上代碼使用的是writeLoop(),再舉一個readLoop()的例子 ~~~ package main import "fmt" // select模式,讀取channel func readLoop(c, quit chan int) { // 開始一個死循環 for { // 通過select等待通道c和quit,看那個有反應,就執行對應的case語句中的代碼 select { case x := <-c: // 如果通道c讀取數據成功,執行這里的計算邏輯 fmt.Println(x) case <-quit: // 如果收到通道quit的數據,就退出函數 fmt.Println("quit") return } } } func main() { // 定義一個channel,用來數據通訊 channel := make(chan int) // 定義一個channel,用來傳遞停止通知 quit := make(chan int) // 創建一個協程,用來寫channel數據 go func() { for i := 0; i < 10; i++ { // 循環從channel通道中寫10次數據,每次寫操作都會觸發channel的select模式 channel <- i } // 往quit通道中發送數據0,通知readLoop函數退出,主協程就結束了 quit <- 0 }() // 開啟channel select模式 readLoop(channel, quit) fmt.Println("done") } ~~~ > 如果select語句有多個分支滿足條件,那么它會隨機選擇一個執行。 ~~~ package main import ( "fmt" ) func main() { channel := make(chan string) go func() { select { // x 和 y都滿足條件,會隨機執行 case x := <-channel: fmt.Println(x+" from x") case y := <-channel: fmt.Println(y+" from y") default: // 如果有 default 子句,沒有滿足條件情況下,會執行該語句 // 如果沒有 default 子句,select 將阻塞,直到滿足條件后執行 fmt.Println("沒有滿足條件,select語句結束") } }() channel <- "haha" for { ; } } ~~~
                  <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>

                              哎呀哎呀视频在线观看