最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang中channel通道的實(shí)現(xiàn)

 更新時(shí)間:2026年03月17日 10:23:15   作者:X_PENG  
本文主要介紹了golang中channel通道的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

簡介-是什么、有什么用

channel字面意思是“通道”,用于goroutine之間進(jìn)行通信、同步

Goroutine 和 channel 是 Go 語言并發(fā)編程的兩大基石。Goroutine用于執(zhí)行并發(fā)任務(wù),channel用于 goroutine之間的通信、同步。

看個簡單demo:

package main

import (
   "log"
   "time"
)

var logger = log.Default()

func main() {
   c1 := make(chan int)

   go func() {
      logger.Println("go sleep start")
      time.Sleep(3 * time.Second)
      logger.Println("go sleep end, send start")
      c1 <- 1
      logger.Println("send end")
   }()

   logger.Println("main receive start")
   i, ok := <-c1
   logger.Printf("main receive end, i:%d, ok:%t\n", i, ok)
}

運(yùn)行程序可以看到main協(xié)程從通道讀取值時(shí)會阻塞,直到另一個協(xié)程往通道發(fā)送數(shù)據(jù),才會喚醒main協(xié)程。

CSP模型

與主流語言通過共享內(nèi)存來進(jìn)行并發(fā)控制方式不同,Go 語言采用了 CSP 模型。

共享內(nèi)存存在競態(tài)問題,需要加鎖同步,會造成性能問題。

CSP (Communicating Sequential Process ),即通信順序進(jìn)程, 是一種并發(fā)編程模型,是一個很強(qiáng)大的并發(fā)數(shù)據(jù)模型,是上個世紀(jì)七十年代提出的,用于描述兩個獨(dú)立的并發(fā)實(shí)體通過共享的通訊 channel(管道)進(jìn)行通信的并發(fā)模型。

強(qiáng)調(diào)通信,有這么一句話:

不要通過共享內(nèi)存來通信,而要通過通信來實(shí)現(xiàn)內(nèi)存共享。

Go語言通過協(xié)程Goroutine和通道Channel實(shí)現(xiàn)了 CSP 模型。go語言并沒有完全實(shí)現(xiàn)了CSP模型的所有理論,僅借用了 process和channel這兩個概念(分別對應(yīng)go語言的goroutine和channel):process是并發(fā)執(zhí)行的實(shí)體,每個實(shí)體之間通過channel通訊來實(shí)現(xiàn)數(shù)據(jù)共享。

channel詳解

channel具有如下特性:

  • 并發(fā)安全
  • 先進(jìn)先出
  • 能阻塞和喚醒goroutine

channel類型

channel是go語言的一種特殊類型,它是一個引用類型,因此未初始化時(shí)其默認(rèn)零值是nil。

  1. 定義channel變量:
var 變量名稱 chan 元素類型
  • 元素類型,是指channel通道中元素的具體類型。

例子:

var c1 chan int
var c2 chan string
var c3 chan bool
var c4 chan []int
  1. 初始化channel,使用make

未初始化,默認(rèn)零值是nil,對nil通道發(fā)送或接收都會一直阻塞。

make(chan 元素類型, [緩沖區(qū)容量])
  • 緩沖區(qū)容量:是可選參數(shù),不指定或?yàn)?則創(chuàng)建無緩沖通道,指定且大于0則創(chuàng)建有緩沖通道。

例子:

c1 := make(chan int)
c2 := make(chan int, 1)

channel的操作

三種操作:

  • 發(fā)送(即寫操作):往通道中發(fā)送數(shù)據(jù)
  • 接收(即讀操作):從通道中讀取數(shù)據(jù)
  • 關(guān)閉

發(fā)送和接收使用<-符號。

發(fā)送

ch <- 10 // 把10發(fā)送到ch中

發(fā)送什么時(shí)候會阻塞?
當(dāng)通道未關(guān)閉且緩沖區(qū)滿時(shí),發(fā)送數(shù)據(jù)就會阻塞,直到有其他協(xié)程消費(fèi)數(shù)據(jù)使緩沖區(qū)不滿才不再阻塞。

接收

x := <- ch // 接收并賦值
<-ch       // 僅接收

接收什么時(shí)候會阻塞?
當(dāng)通道未關(guān)閉且緩沖區(qū)空(無數(shù)據(jù)可讀)時(shí),接收數(shù)據(jù)就會阻塞,直到有其他協(xié)程向通道生產(chǎn)數(shù)據(jù)使緩沖區(qū)不空、有數(shù)據(jù)可讀時(shí)才不再阻塞。

多返回值模式,接收操作可以使用多返回值模式:

value, ok := <- ch
  • ok:表示是否成功從通道中讀取數(shù)據(jù)。false,即未成功讀取,表示通道為空、無數(shù)據(jù)可讀了,且此時(shí)通道肯定關(guān)閉了,不然接收操作會阻塞。

注意:接收操作不阻塞,只有兩種情況:1. 有數(shù)據(jù)可讀、通道不空;2. 若無數(shù)據(jù)可讀,則通道必須關(guān)閉了

  • value:從通道中讀取的值,若ok為false,則value是通道元素的數(shù)據(jù)類型的零值。

個人認(rèn)為,多返回值模式的作用:如果ok返回false,則表示通道空了且已關(guān)閉。

nil通道

chan類型的默認(rèn)零值是nil,對nil通道進(jìn)行讀、寫都會阻塞。

關(guān)閉通道

使用close函數(shù)

close(ch)

注意:

  • 通常由發(fā)送方執(zhí)行關(guān)閉操作
  • 關(guān)閉通道不是必須的(不像關(guān)閉文件是必須的),一般僅在接收方明確需要關(guān)閉信號時(shí)才執(zhí)行關(guān)閉操作

關(guān)閉后的通道有如下特點(diǎn):

  • 不能再發(fā)送,再發(fā)送數(shù)據(jù)會panic
  • 可以接收。通道被關(guān)閉,仍然可以讀取未讀完的數(shù)據(jù);當(dāng)通道為空(即沒有數(shù)據(jù)了),再讀取也不會造成阻塞,而是會返回對應(yīng)數(shù)據(jù)類型的零值

重要:已關(guān)閉通道,一定不會阻塞讀取操作

  1. 重復(fù)關(guān)閉會panic

close最佳實(shí)踐:

  1. 非必要不要close
  2. 比較常見的是將close作為一種通知機(jī)制,通過close告訴消費(fèi)者我關(guān)閉了,此時(shí)消費(fèi)者消費(fèi)就不會再阻塞了。

for range接收通道數(shù)據(jù)

for range可不斷從通道中接收數(shù)據(jù),當(dāng)通道為空且已關(guān)閉了,會退出循環(huán)(因?yàn)闉榭涨乙殃P(guān)閉的通道是不可能再有數(shù)據(jù)了);當(dāng)通道為空但未關(guān)閉,會阻塞直到通道有數(shù)據(jù)。

示例:

func main() {
   c1 := make(chan int, 3)

   go func() {
      for i := 0; i < 10; i++ {
         <-time.After(time.Second)
         c1 <- i
      }

      <-time.After(5 * time.Second)

      for i := 90; i < 100; i++ {
         <-time.After(time.Second)
         c1 <- i
      }

      <-time.After(5 * time.Second)
      log.Default().Println("---close chan---")
      close(c1)
   }()

   go func() {
      for i := range c1 {
         log.Default().Println(i)
      }
      log.Default().Println("---chan closed---")
   }()

   for {

   }
}

單向通道

是什么?

只能發(fā)送或只能接收的通道就是單向通道。

為什么要單向通道?

某些場景下我們想限制使用者對通道的操作:只允許發(fā)送或接收,為了表明這種意圖并防止被濫用,所以go語言提供了單向channel。

如何使用?

定義單向通道:

箭頭<-和關(guān)鍵字chan的相對位置表明了當(dāng)前通道允許的操作,這種限制將在編譯階段進(jìn)行檢測。

<- chan int // 只接收通道,只能接收不能發(fā)送
chan <- int // 只發(fā)送通道,只能發(fā)送不能接收

「只接收channel」不允許close,因?yàn)橐话愣际前l(fā)送方來close通道。

通道類型轉(zhuǎn)換:

雙向通道可以轉(zhuǎn)成單向通道(是隱式轉(zhuǎn)換),但反之不行。

示例:

生產(chǎn)者只能向channel發(fā)送數(shù)據(jù),消費(fèi)者只能從channel接收數(shù)據(jù),所以使用單向channel

func main() {
   c1 := make(chan int, 1)
   go producer(c1)
   go consumer(c1)
   for {
   }
}
func producer(ch chan<- int) {
   for i := 0; i < 10; i++ {
      <-time.After(time.Second)
      ch <- i
   }
   log.Default().Println("producer. close chan")
   // 發(fā)送通道可close
   close(ch)
}

func consumer(ch <-chan int) {
   for i := range ch {
      log.Default().Println("consume:", i)
      // 接收通過不能close
      //close(ch)
   }
   log.Default().Println("consumer. chan closed")
}

select多路復(fù)用

作用:

可以同時(shí)監(jiān)聽多個channel的發(fā)送或接收操作。

如何使用?

  • 類似switch語句,select也有一系列case分支和一個default分支,每個case分支可以監(jiān)聽一個channel的發(fā)送或接收操作,若可接收或可發(fā)送,則匹配該case分支;沒有任何case匹配,則走default分支。
  • 若沒有default分支,select會一直阻塞直到某個case匹配。
  • 若沒有case也沒有default分支,select會一直阻塞。
  • 若同時(shí)有多個case滿足,select會隨機(jī)選擇一個case執(zhí)行。

使用方式如下:

select {
case <-ch1:
    //...
case data := <-ch2:
    //...
case ch3 <- 10:    
    //...
default:
    //默認(rèn)操作
}

示例:

func main() {
   ch := make(chan int, 1)
   for i := 0; i < 10; i++ {
      select {
      case ch <- i:
         log.Default().Println("send")
      case x := <-ch:
         log.Default().Println("receive, x:", x)
      default:
         log.Default().Println("default")
      }

      // 會panic panic: send on closed channel
      //if i == 0 {
      // close(ch)
      //}
   }
}

無緩沖channel和有緩沖channel

make(chan 元素類型, [緩沖區(qū)容量])

創(chuàng)建channel時(shí):

  • 未指定緩沖區(qū)容量或?yàn)?,則創(chuàng)建的是無緩沖channel
  • 指定了緩沖區(qū)容量且大于0,則創(chuàng)建的是有緩沖channel

無緩沖channel

沒有緩沖區(qū),channel中不能緩存數(shù)據(jù)

  • 發(fā)送操作一定會阻塞,直到有人接收
  • 接收操作一定會阻塞,直到有人發(fā)送

有緩沖channel

有緩沖區(qū),channel中可以緩存數(shù)據(jù)

  • 僅當(dāng)緩沖區(qū)滿時(shí),發(fā)送操作才阻塞,直到有人接收
  • 僅當(dāng)緩沖區(qū)空時(shí),接收操作才阻塞,直到有人發(fā)送

len和cap方法

  • len方法可以返回通道中元素的個數(shù)
  • cap方法可以返回通道的緩沖區(qū)容量

對于「無緩沖channel」,len和cap都是0。

問題

channel有一個發(fā)送方,多個接收方怎么辦?

多個接收方共同消費(fèi)channel中的數(shù)據(jù)。

示例:

func main() {
   ch1 := make(chan int, 1)
   go consumer(ch1)
   go consumer2(ch1)
   go producer(ch1)
   for {

   }
}
func producer(ch chan<- int) {
   for i := 0; i < 10; i++ {
      <-time.After(time.Second)
      ch <- i
   }
   log.Default().Println("producer. close chan")
   // 發(fā)送通道可close
   close(ch)
   log.Default().Println("producer. end")
}

func consumer(ch <-chan int) {
   for i := range ch {
      log.Default().Println("consumer consume:", i)
   }
   log.Default().Println("consumer. chan closed")
}
func consumer2(ch <-chan int) {
   for i := range ch {
      log.Default().Println("consumer2 consume:", i)
   }
   log.Default().Println("consumer2. chan closed")
}

運(yùn)行結(jié)果:

2022/10/30 01:46:46 consumer consume: 0
2022/10/30 01:46:47 consumer2 consume: 1
2022/10/30 01:46:48 consumer consume: 2
2022/10/30 01:46:49 consumer2 consume: 3
2022/10/30 01:46:50 consumer consume: 4
2022/10/30 01:46:51 consumer2 consume: 5
2022/10/30 01:46:52 consumer consume: 6
2022/10/30 01:46:53 consumer2 consume: 7
2022/10/30 01:46:54 consumer consume: 8
2022/10/30 01:46:55 consumer2 consume: 9
2022/10/30 01:46:55 producer. close chan
2022/10/30 01:46:55 producer. end
2022/10/30 01:46:55 consumer. chan closed
2022/10/30 01:46:55 consumer2. chan closed

goroutine泄漏

goroutine泄漏是什么?

是指goroutine一直阻塞而無法被回收。

不正確的使用channel可能導(dǎo)致goroutine泄漏,如下:

func main() {
   ch := make(chan int)

   go test(ch)
   select {
   case <-ch:
      log.Default().Println("receive")
   case <-time.After(time.Second):
      log.Default().Println("time")
   }

   for {

   }
}

func test(ch chan int) {
   log.Default().Println("test run")
   <-time.After(3 * time.Second)
   ch <- 1
   log.Default().Println("test end")
}

運(yùn)行結(jié)果:

2022/10/30 01:55:17 test run
2022/10/30 01:55:18 time

發(fā)生了goroutine泄漏,test方法的goroutine一直阻塞了,因?yàn)閙ain gorutine無法接收通道

到此這篇關(guān)于golang中channel通道的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang channel通道內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言metrics應(yīng)用監(jiān)控指標(biāo)基本使用說明

    Go語言metrics應(yīng)用監(jiān)控指標(biāo)基本使用說明

    這篇文章主要為大家介紹了Go語言metrics應(yīng)用監(jiān)控指標(biāo)的基本使用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • Go?modules?replace解決Go依賴引用問題

    Go?modules?replace解決Go依賴引用問題

    這篇文章主要為大家介紹了Go?modules?replace解決Go依賴引用問題,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go語言中防止敏感數(shù)據(jù)意外泄露的幾種方法

    Go語言中防止敏感數(shù)據(jù)意外泄露的幾種方法

    這篇文章主要介紹了在Go語言中優(yōu)雅地處理敏感數(shù)據(jù)的方法,通過使用接口來控制格式化、日志記錄、序列化等行為,避免敏感信息泄露,需要的朋友可以參考下
    2026-01-01
  • Golang中channel使用的一些小技巧

    Golang中channel使用的一些小技巧

    這篇文章主要介紹了Golang中channel使用的一些小技巧,本文講解了關(guān)閉2次、讀取的時(shí)候channel提前關(guān)閉了、向已經(jīng)關(guān)閉的channel寫數(shù)據(jù)等技巧及這實(shí)例代碼,需要的朋友可以參考下
    2015-07-07
  • GoLang完整實(shí)現(xiàn)快速列表

    GoLang完整實(shí)現(xiàn)快速列表

    這篇文章主要介紹了GoLang完整實(shí)現(xiàn)快速列表,列表是一種非連續(xù)的存儲容器,由多個節(jié)點(diǎn)組成,節(jié)點(diǎn)通過一些 變量 記錄彼此之間的關(guān)系,列表有多種實(shí)現(xiàn)方法,如單鏈表、雙鏈表等
    2022-12-12
  • Golang實(shí)現(xiàn)心跳機(jī)制的示例詳解

    Golang實(shí)現(xiàn)心跳機(jī)制的示例詳解

    這篇文章主要為大家詳細(xì)介紹了Golang實(shí)現(xiàn)心跳機(jī)制的相關(guān)知識,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下
    2024-04-04
  • go語言的panic和recover函數(shù)用法實(shí)例

    go語言的panic和recover函數(shù)用法實(shí)例

    今天小編就為大家分享一篇關(guān)于go語言的panic和recover函數(shù)用法實(shí)例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • 解析Golang中的GoPath和GoModule

    解析Golang中的GoPath和GoModule

    在Golang中,有兩個概念非常容易弄錯,第一個就是GoPath,第二個則是GoModule,很多初學(xué)者不清楚這兩者之間的關(guān)系,也就難以清晰地了解項(xiàng)目的整體結(jié)構(gòu),今天通過本文給大家介紹下Golang中的GoPath和GoModule相關(guān)知識,感興趣的朋友一起看看吧
    2022-02-02
  • 一文詳解如何在Golang中實(shí)現(xiàn)JWT認(rèn)證與授權(quán)

    一文詳解如何在Golang中實(shí)現(xiàn)JWT認(rèn)證與授權(quán)

    在現(xiàn)代Web應(yīng)用中,安全性是一個非常重要的課題,JWT作為一種常用的認(rèn)證與授權(quán)機(jī)制,已被廣泛應(yīng)用于各種系統(tǒng)中,下面我們就來看看如何在Golang中實(shí)現(xiàn)JWT認(rèn)證與授權(quán)吧
    2025-03-03
  • 詳解Go語言中的內(nèi)存對齊

    詳解Go語言中的內(nèi)存對齊

    前面我們學(xué)習(xí)了Go語言空結(jié)構(gòu)體詳解,最近又在看unsafe包的知識,在查閱相關(guān)資料時(shí)不免會看到內(nèi)存對齊相關(guān)的內(nèi)容。雖然不會,但可以學(xué)呀,那么這篇文章,我們就一起來看下什么是內(nèi)存對齊吧
    2022-10-10

最新評論

武隆县| 合阳县| 石楼县| 南丰县| 威宁| 麻城市| 桃园市| 石泉县| 镇雄县| 齐齐哈尔市| 龙游县| 上饶县| 丹凤县| 石屏县| 许昌市| 沙湾县| 灵丘县| 法库县| 包头市| 新平| 平顺县| 宝应县| 尼勒克县| 汤原县| 郑州市| 司法| 中西区| 桐乡市| 乌拉特后旗| 辰溪县| 本溪市| 乐业县| 平谷区| 双辽市| 华容县| 金昌市| 托里县| 精河县| 屏东县| 达孜县| 伊宁县|