<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Golang基礎筆記十之goroutine和channel

      本文首發于公眾號:Hunter后端

      原文鏈接:Golang基礎筆記十之goroutine和channel

      這一篇介紹 Golang 里的 goroutine 和 channel 通道。

      以下是本篇筆記目錄:

      1. goroutine
      2. channel
      3. goroutine 與 channel 的使用

      1、goroutine

      goroutine 是一種輕量級線程(用戶態線程),由 Go 運行時管理而非操作系統,它是 Go 并發模型的核心,能高效處理大量并發任務。

      1. goroutine 的使用

      goroutine 的使用非常簡單,直接使用 go + 函數 即可啟動一個 goroutine:

      package main
      
      import (
      	"fmt"
      	"time"
      )
      
      func PrintGoroutineInfo() {
          fmt.Println("msg from goroutine")
      }
      
      func main() {
          go PrintGoroutineInfo()
          time.Sleep(1 * time.Millisecond)
          fmt.Println("msg from main")
      }
      

      2. 匿名函數使用 goroutine

      func main() {
          go func() {
              fmt.Println("msg from goroutine")
          }()
          time.Sleep(1 * time.Second)
      }
      

      而如果 goroutine 運行的函數有返回值,想要獲取函數的返回值應該如何操作呢?

      或者當我們使用 goroutine 的時候,如何使主 goroutine 等待并發的 goroutine 執行完畢再接著往后執行呢?

      其中一個方法就是使用 channel 來獲取返回值,以及使用 channel 的阻塞狀態來等待并發的 goroutine 執行完畢。

      2、channel

      channel,即通道,可用于在 goroutine 之間傳遞數據和同步狀態。

      1. channel 的聲明與創建

      channel 是強類型的,每個 channel 只能傳遞一種類型的數據。

      1) 無緩沖通道

      比如我們聲明一個傳遞 int 類型的 channel:

      var ch chan int
      

      或者直接創建一個傳遞 int 數據的通道:

      ch := make(chan int)
      
      2) 有緩沖通道

      在創建 channel 的時候,如果不指定容量,那么則稱其為無緩沖通道,如果指定了容量,則為有緩沖通道,比如下面創建一個容量為 3 的通道:

      ch := make(chan int, 3)
      

      2. channel 的操作

      發送數據

      向一個 channel 發送數據的操作如下:

      ch <- 21
      

      接收數據

      從一個 channel 中接收數據的操作如下:

      x := <-ch
      

      或者僅僅是接收數據但不使用,可以直接丟棄:

      <-ch
      

      使用 range 遍歷 channel

      也可以使用 range 的方式遍歷從 channel 中接收數據,但是需要在通道關閉后:

      for x := range ch {
          fmt.Println(x)
      }
      

      關閉 channel

      關閉一個 channel 的操作如下:

      close(ch)
      

      3、goroutine 與 channel 的使用

      下面介紹幾種 channel 在使用中的特殊情況。

      1. 阻塞情況

      對于 channel 的使用,如果使用不慎,有可能會造成阻塞,以下是幾種阻塞的情況

      1) 無緩沖通道

      對于無緩沖通道而言,發送和接收的操作必須同時發生,否則會進入阻塞狀態。

      
      func CapZeroChannel(ch chan int) {
          time.Sleep(5 * time.Second)
          ch <- 1
          fmt.Println("inner func, send msg:", time.Now().Format("2006-01-02 15:04:05"))
      }
      
      func main() {
          ch := make(chan int)
      
          go CapZeroChannel(ch)
          fmt.Println("before func:", time.Now().Format("2006-01-02 15:04:05"))
      
          x := <-ch
          fmt.Println("after func:", time.Now().Format("2006-01-02 15:04:05"))
      
          fmt.Println(x)
      }
      
      

      在上面的操作中,最后輸出的結果如下:

      before func: 2025-06-28 23:33:03
      inner func, send msg: 2025-06-28 23:33:08
      after func: 2025-06-28 23:33:08
      

      可以看到,在并發的 CapZeroChannel() 函數中,發送數據前等待了 5 秒鐘,同時在主 goroutine,也就是 main 函數中,通道接收值的地方發生了阻塞,直到發送方把數據通過 channel 發送過來,才接著往后執行。

      而如果我們將等待的地方放在接收前:

      func CapZeroChannel(ch chan int) {
          ch <- 1
          fmt.Println("inner func, send msg:", time.Now().Format("2006-01-02 15:04:05"))
      }
      
      func main() {
          ch := make(chan int)
      
          go CapZeroChannel(ch)
          fmt.Println("before func:", time.Now().Format("2006-01-02 15:04:05"))
      
          time.Sleep(5 * time.Second)
          x := <-ch
          fmt.Println("after func:", time.Now().Format("2006-01-02 15:04:05"))
      
          fmt.Println(x)
      }
      

      最后輸出的信息如下:

      before func: 2025-06-28 23:37:32
      after func: 2025-06-28 23:37:37
      inner func, send msg: 2025-06-28 23:37:37
      

      可以看到發送的地方也同時發生了阻塞。

      通過這兩個示例,可以證實前面的觀點,即 對于無緩沖通道而言,發送和接收的操作必須同時發生,否則會進入阻塞狀態。

      2) 有緩沖通道

      對于有緩沖通道來說,阻塞的情況會發生在向已滿的通道里發送數據,或者從空的通道里接收數據,下面是各自的示例:

      向已滿的通道里發送數據

      當我們向已滿的通道里發送數據,會發生阻塞,下面是代碼示例:

      func SendMsgToChannel(ch chan int) {
          ch <- 1
          fmt.Println("send msg to channel: ", 1, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          ch <- 2
          fmt.Println("send msg to channel: ", 2, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          ch <- 3
          fmt.Println("send msg to channel: ", 3, " at: ", time.Now().Format("2006-01-02 15:04:05"))
      
          ch <- 4
          fmt.Println("send msg to channel: ", 4, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          close(ch)
      }
      
      func main() {
          ch := make(chan int, 3)
      
          go SendMsgToChannel(ch)
      
          time.Sleep(5 * time.Second)
      
          for x := range ch {
              fmt.Println("receive msg from channel: ", x, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          }
      
      }
      

      可以看到輸出的信息如下:

      send msg to channel:  1  at:  2025-06-29 00:36:24
      send msg to channel:  2  at:  2025-06-29 00:36:24
      send msg to channel:  3  at:  2025-06-29 00:36:24
      receive msg from channel:  1  at:  2025-06-29 00:36:29
      receive msg from channel:  2  at:  2025-06-29 00:36:29
      receive msg from channel:  3  at:  2025-06-29 00:36:29
      receive msg from channel:  4  at:  2025-06-29 00:36:29
      send msg to channel:  4  at:  2025-06-29 00:36:29
      

      前面向通道里發送三條數據,把有緩沖通道占滿了,但是在接收前 sleep 了五秒鐘,所以沒有及時從通道里接收數據,當向通道里發送第四條數據的時候就會發生阻塞。

      五秒鐘后,主 goroutine 開始從 channel 里消費數據,第四條數據才往里寫入。

      從空通道里接收數據

      如果從空通道里接收數據,也會發生阻塞,下面是代碼示例:

      func SendMsgToChannel(ch chan int) {
      
          time.Sleep(3 * time.Second)
      
          ch <- 1
          fmt.Println("send msg to channel: ", 1, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          ch <- 2
          fmt.Println("send msg to channel: ", 2, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          ch <- 3
          fmt.Println("send msg to channel: ", 3, " at: ", time.Now().Format("2006-01-02 15:04:05"))
      
          ch <- 4
          fmt.Println("send msg to channel: ", 4, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          close(ch)
      }
      
      func main() {
          ch := make(chan int, 3)
      
          go SendMsgToChannel(ch)
          fmt.Println("start receive msg from channel at: ", time.Now().Format("2006-01-02 15:04:05"))
          for x := range ch {
              fmt.Println("receive msg from channel: ", x, " at: ", time.Now().Format("2006-01-02 15:04:05"))
          }
      }
      

      其輸出信息如下:

      start receive msg from channel at:  2025-06-29 00:41:24
      receive msg from channel:  1  at:  2025-06-29 00:41:27
      send msg to channel:  1  at:  2025-06-29 00:41:27
      send msg to channel:  2  at:  2025-06-29 00:41:27
      send msg to channel:  3  at:  2025-06-29 00:41:27
      send msg to channel:  4  at:  2025-06-29 00:41:27
      receive msg from channel:  2  at:  2025-06-29 00:41:27
      receive msg from channel:  3  at:  2025-06-29 00:41:27
      receive msg from channel:  4  at:  2025-06-29 00:41:27
      

      可以看到,在發送信息前 sleep 了 3 秒,因此接收方也等待了 3 秒才能開始接收數據,在這之前一直是處于阻塞狀態。

      2. 通道的關閉

      通道在關閉后,不可以再向其中發送數據,但是還可以從中接收數據。

      func PrintGoroutineInfo(ch chan int) {
          fmt.Println("msg from goroutine")
          time.Sleep(1 * time.Second)
          ch <- 2
          close(ch)
      }
      
      func main() {
          ch := make(chan int)
          go PrintGoroutineInfo(ch)
          x := <-ch
          fmt.Println(x)
      }
      

      3. 發送和接收通道的類型

      前面我們將通道作為參數傳遞給函數,其類型僅僅是通道類型,如果我們想要在代碼層面使其更嚴謹,比如某個函數中只允許發送或者接收數據,我們在其類型進行更嚴謹的聲明。

      比如發送通道我們可以對其聲明為 chan<-,接收通道可以對其聲明為 <-chan,下面是代碼示例:

      func SendMsg(ch chan<- int) {
          ch <- 4
          fmt.Println("send msg: ")
      }
      
      func ReceiveMsg(ch <-chan int) {
          x := <-ch
          fmt.Println("receive msg: ", x)
      }
      
      func main() {
          ch := make(chan int, 3)
      
          go SendMsg(ch)
          go ReceiveMsg(ch)
      
          time.Sleep(1 * time.Second)
          fmt.Println("end")
      }
      

      在這篇筆記中,我們介紹 goroutine 和 channel 在 Golang 中的使用,比如如何使用 goroutine 開啟一個并發操作,如何使用 channel 在 goroutine 間進行通信。

      但是關于 goroutine 之間的一些并發控制與鎖相關的一些概念我們將在之后的筆記中進行更詳細的介紹。

      posted @ 2025-07-09 21:54  XHunter  閱讀(321)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 垣曲县| 亚洲欧洲色图片网站| 亚洲最大的成人网站| 房东老头揉捏吃我奶头影片| 国内自拍av在线免费| 国内少妇人妻丰满av| 少妇被粗大的猛烈进出| 国产精品十八禁在线观看| 妺妺窝人体色www看美女| 国产v综合v亚洲欧美大天堂| 免费视频爱爱太爽了| 中文字幕一区日韩精品| 重口SM一区二区三区视频| 国产成人亚洲无码淙合青草| 三级网站视频在在线播放| 国产免费久久精品99reswag| 国产睡熟迷奷系列网站| 亚洲av成人三区国产精品| 97精品尹人久久大香线蕉| 成年无码av片在线蜜芽| 高清国产av一区二区三区| 久久精品蜜芽亚洲国产av| 国产人成视频在线观看| 日产日韩亚洲欧美综合下载| 亚洲精品免费一二三区| 国产情侣草莓视频在线| 野花韩国高清电影| 久久精品女人天堂av免费观看| 蜜芽亚洲AV无码精品国产午夜| 亚洲av日韩av永久无码电影| 成人精品视频一区二区三区| 亚洲夜夜欢一区二区三区| 最新国产精品拍自在线观看| 久久国产免费观看精品3| 久久国产精品老人性| 亚洲国产成人无码AV在线影院L| 广宗县| 欧美成人黄在线观看| 午夜在线不卡| 色欲综合久久中文字幕网| 乌克兰丰满女人a级毛片右手影院|