網站首頁 編程語言 正文
一、什么是通道類型
Go 語言中的通道(channel)是一種特殊的類型。通道像一個傳送帶或者隊列,總是遵循先入先出(First In First Out)的規則,保證收發數據的順序。每一個通道都是一個具體類型的導管,也就是聲明channel的時候需要為其指定元素類型。
如果說goroutine是Go程序并發的執行體,channel就是它們之間的連接。channel是可以讓一個goroutine發送特定值到另一個goroutine的通信機制。
二、通道產生的原因
雖然可以使用共享內存進行數據交換,但是共享內存在不同的goroutine中容易發生競態問題。為了保證數據交換的正確性,必須使用互斥量對內存進行加鎖,這種做法勢必造成性能問題。
Go語言的并發模型是CSP(Communicating Sequential Processes),提倡通過通信共享內存而不是通過共享內存而實現通信。
三、聲明channel
語法:
var 變量 chan 元素類型 ?
例:
var ch1 chan int // 聲明一個傳遞整型的通道 var ch2 chan bool // 聲明一個傳遞布爾型的通道 var ch3 chan []int // 聲明一個傳遞int切片的通道
四、創建channel
語法:
make(chan 元素類型, [緩沖大小])
注意: 聲明的通道后需要使用make函數初始化之后才能使用。channel的緩沖大小是可選的。
例:
ch4 := make(chan int, 3) ch5 := make(chan bool) ch6 := make(chan []int)
五、channel相關操作
1、發送值
將一個值發送到通道中。
例:
ch <- 10 // 把10發送到ch中
2、接收值
從一個通道中接收值。
例:
x := <- ch // 從ch中接收值并賦值給變量x <-ch // 從ch中接收值,忽略結果
3、關閉通道
例:
close(ch)
3.1 注意
只有在通知接收方goroutine所有的數據都發送完畢的時候才需要關閉通道。通道是可以被垃圾回收機制回收的,它和關閉文件是不一樣的,在結束操作之后關閉文件是必須要做的,但關閉通道不是必須的。
3.2 特點
- 對一個關閉的通道再發送值就會導致panic。
- 對一個關閉的通道進行接收會一直獲取值直到通道為空。
- 對一個關閉的并且沒有值的通道執行接收操作會得到對應類型的零值。
- 關閉一個已經關閉的通道會導致panic。
六、通道類型
1、無緩沖通道
無緩沖的通道只有在有人接收值的時候才能發送值。就像你住的小區沒有快遞柜和代收點,快遞員給你打電話必須要把這個物品送到你的手中,簡單來說就是無緩沖的通道必須有接收才能發送。
語法:
ch := make(chan type)
例:
func recv(c chan int) { ret := <-c fmt.Println("接收成功", ret) } func main() { ch := make(chan int) go recv(ch) // 啟用goroutine從通道接收值 ch <- 10 fmt.Println("發送成功") }
分析: 無緩沖通道上的發送操作會阻塞,直到另一個goroutine在該通道上執行接收操作,這時值才能發送成功,兩個goroutine將繼續執行。相反,如果接收操作先執行,接收方的goroutine將阻塞,直到另一個goroutine在該通道上發送一個值。
2、有緩沖通道
只要通道的容量大于零,那么該通道就是有緩沖的通道,通道的容量表示通道中能存放元素的數量。就像你小區的快遞柜只有那么個多格子,格子滿了就裝不下了,就阻塞了,等到別人取走一個快遞員就能往里面放一個。
語法:
ch := make(chan type, [cap])
例:
func main() { ch := make(chan int, 1) // 創建一個容量為1的有緩沖區通道 ch <- 10 fmt.Println("發送成功") }
七、單向通道
有的時候我們會將通道作為參數在多個任務函數間傳遞,很多時候我們在不同的任務函數中使用通道都會對其進行限制,比如限制通道在函數中只能發送或只能接收。
語法:
chan<- int ?是一個只能發送的通道,可以發送但是不能接收;
<-chan int ?是一個只能接收的通道,可以接收但是不能發送。
例:
func counter(out chan<- int) { ? ? for i := 0; i < 100; i++ { ? ? ? ? out <- i ? ? } ? ? close(out) } func squarer(out chan<- int, in <-chan int) { ? ? for i := range in { ? ? ? ? out <- i * i ? ? } ? ? close(out) } func printer(in <-chan int) { ? ? for i := range in { ? ? ? ? fmt.Println(i) ? ? } } func main() { ? ? ch1 := make(chan int) ? ? ch2 := make(chan int) ? ? go counter(ch1) ? ? go squarer(ch2, ch1) ? ? printer(ch2) }
注意: 在函數傳參及任何賦值操作中將雙向通道轉換為單向通道是可以的,但反過來是不可以的。
八、從通道循環取值
例:
// channel 練習 func main() { ch1 := make(chan int) ch2 := make(chan int) // 開啟goroutine將0~100的數發送到ch1中 go func() { for i := 0; i < 100; i++ { ch1 <- i } close(ch1) }() // 開啟goroutine從ch1中接收值,并將該值的平方發送到ch2中 go func() { for { i, ok := <-ch1 // 通道關閉后再取值ok=false if !ok { break } ch2 <- i * i } close(ch2) }() // 在主goroutine中從ch2中接收值打印 for i := range ch2 { // 通道關閉后會退出for range循環 fmt.Println(i) } }
分析: 有兩種方式在接收值的時候判斷通道是否被關閉,我們通常使用的是for range的方式。
原文鏈接:https://blog.csdn.net/change_any_time/article/details/128978799
相關推薦
- 2023-01-08 react?頁面加載完成后自動執行標簽的點擊事件的兩種操作方法_React
- 2022-05-12 android ViewModel+LiveData簡單使用
- 2022-12-30 解決React報錯The?tag?is?unrecognized?in?this?browser_R
- 2023-01-18 GoLang完整實現快速列表_Golang
- 2022-07-02 python?np.arange?步長0.1的問題需要特別注意_python
- 2022-07-02 C++精要分析lambda表達式的使用_C 語言
- 2022-02-28 ./node_modules/taro-ui/dist/weapp/index.ts Module
- 2022-09-17 C/C++?中實現讓控制臺暫停的方法_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支