中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言基礎并發channel

發布時間:2021-09-03 11:50:07 來源:億速云 閱讀:174 作者:chen 欄目:web開發

這篇文章主要講解了“Go語言基礎并發channel”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Go語言基礎并發channel”吧!

為什么需要channel

channel在Go中,也叫做管道,是用來多線程之間共享數據的。

通常情況下,在Go中共享數據用的也是channel,但是在Go有兩種共享數據方式。

  • 共享內存實現通訊。

  • 通過管道(channel)通訊(推薦)。

為啥子共享內存通訊不太推薦?

示例代碼:多線程修改一個值。

函數

func Calc() {     defer wg.Done()     NUM = NUM - 1 }

main

var NUM = 100 var wg sync.WaitGroup  func main() {     for i := 0; i<100;i++  {         wg.Add(1)         go Calc() }     wg.Wait()     fmt.Println(NUM) }

執行結果

Go語言基礎并發channel

沒錯,是2,懵了吧,哈哈哈,理論應該是0才對呀。

這是為啥?

這就是共享內存不太推薦的原因,我們的代碼已經是多線程了。

在第一個函數代碼中,第3行,NUM = NUM - 1。

如果多個線程同時執行到這一行,并且沒有加鎖,就會出現數據錯亂。

那該怎么做呢?

加鎖,加鎖可以保證某一段代碼只能被一個線程執行,防止被爭搶。

代碼

func Calc() {     defer wg.Done()     mutex.Lock()     NUM = NUM - 1     mutex.Unlock() }

第3行加鎖,第5行解鎖。

執行結果

Go語言基礎并發channel

這次真的是0的,不管執行幾次。

但是會發現一個問題,如果采用這種方式,需要常常注意競爭問題。

所以不是太推薦,需要考慮的比較多,并且各種加鎖會消耗性能。

channel語法

channel格式

var 變量名 chan 類型 例如 var x1 chan int //x1管道里面只能存int類型數據 var x2 chan string //x2管道里面只能存字符串類型數據

注意

Go語言基礎并發channel

定義管道時,chan int是一個整體,別搞錯了各位。

創建channel

創建channel,只能通過make創建。

格式

var 變量名 = make(chan 類型,[管道大小]) 示例 var chan1 = make(chan int,10)//管道可以放10個int元素 var chan2 = make(chan string,5)//管道可以放5個string元素

channel操作

創建一個管道。

ch = make(chan int,10)

channel是一個管道,就像一個管子。

所以可以像管子里面塞東西,并且能取東西,關閉管道就是這個管道不能用了,里面的值取完就打樣了。

像管子塞東西(發送)ch <- 666。

從管子取東西(接收)var x = <- ch。

關閉管子close(ch)。

注意:channel是先入先出結構,就像這樣。

Go語言基礎并發channel 

注意事項:

  • 如果通道塞滿了,再塞 會阻塞住。

  • 如果通道關閉了,是不能再塞值了,否則會panic。

  • 即使通道關閉了,依然可以取值,直到將管道的值取完,取完后得到的是對應類型零值。

  • 管道不能重復關閉,重復關閉會panic。

無緩沖管道

無緩沖就是這個管道沒有長度,就像這樣。

就像快讀員沒有快遞柜,需要直接將快遞給客戶,如果沒人要就撂攤子。

Go語言基礎并發channel

示例代碼

package main  import (     "fmt" )  //模擬張三 func 張三(x chan string) {     var a = <-x     fmt.Println(a) }  func main() {     //通道沒有長度,就是無緩沖通道     var x = make(chan string)     go 張三(x)     x <- "張三的快遞"     fmt.Println("張三快遞交付成功") }

第16行寫入一個值,同理,張三就要等著去接,如果沒人接,那就完了。

假設注釋第9行代碼。

Go語言基礎并發channel

直接報錯,all goroutines are asleep - deadlock!,這句話的意思是所有的協程都睡著了,死鎖

無緩沖說明通道長度為0,發送一個值會阻塞住。

這就相當于快遞員直接找張三,但是張三沒了,但是快遞員還得一直等著,等等等,然后掛了,終究還是沒送出去。

有緩沖管道

Go語言基礎并發channel

這個就簡單啦,多了一個快遞柜,快遞員直接將快遞仍快遞柜就行了。

示例代碼

package main  import (     "fmt"     "sync" )  var wg sync.WaitGroup  //快遞員,快遞員放10個快遞 func 快遞員(kuaidigui chan string) {     defer wg.Done()     for i := 0; i < 10; i++ {         fmt.Println("快遞員放入了第",i,"快遞")         kuaidigui <- fmt.Sprintf("第%d個快遞", i) }     //放完快遞就關閉了通道     close(kuaidigui) }  //張三,拿走3個快遞 func 張三(kuaidigui chan string) {     defer wg.Done()     for i := 0; i < 3; i++ {         fmt.Println("張三拿走" + <-kuaidigui) } } //李四拿走7個快遞 func 李四(kuaidigui chan string) {     defer wg.Done()     for i := 0; i < 7; i++ {         fmt.Println("李四拿走" + <-kuaidigui) } } func main() {     //快遞柜,10個大小     var 快遞柜 = make(chan string, 10)     wg.Add(3)     go 快遞員(快遞柜)     go 張三(快遞柜)     go 李四(快遞柜)     wg.Wait() }

執行結果

Go語言基礎并發channel 

遍歷channel兩種方式

代碼

func main() {     //快遞柜,10個大小     var ch = make(chan int, 10)     //向管道中發送值     for i := 0; i < 10; i++ {         ch <- i }     //方式一取值     //for {     //i, ok := <-ch     ////取完值ok就是false     //if !ok {     //      //結束循環     //      break     //}     //fmt.Println(i)     //}     //方式二取值     for i:=range ch{         fmt.Println(i) } }

執行結果

Go語言基礎并發channel

報錯是因為我在main中完成了發送值和取值兩個操作,所以會出現上述問題,但是結果是沒有錯的。

單向通道

我們知道通道是可以發送值和取值的,但是某些場景為了安全起見,理論來說只能取值,后者只能發送值。

單向通道通常只在函數參數中體現。

  • 形參 chan<- chan類型只寫。

  • 形參 <-chan chan類型只讀。

修改上述快遞員代碼。

package main  import (     "fmt"     "sync" )  var wg sync.WaitGroup  //快遞員,快遞員放10個快遞,只寫 chan<- string func 快遞員(kuaidigui chan<- string) {     defer wg.Done()     for i := 0; i < 10; i++ {         fmt.Println("快遞員放入了第", i, "快遞")         kuaidigui <- fmt.Sprintf("第%d個快遞", i) }     //放完快遞就關閉了通道     close(kuaidigui) }  //張三,拿走3個快遞,只讀<-chan string func 張三(kuaidigui <-chan string) {     defer wg.Done()     for i := 0; i < 3; i++ {         fmt.Println("張三拿走" + <-kuaidigui) } }  //李四拿走7個快遞 func 李四(kuaidigui <-chan string) {     defer wg.Done()     for i := 0; i < 7; i++ {         fmt.Println("李四拿走" + <-kuaidigui) } } func main() {     //快遞柜,10個大小     var 快遞柜 = make(chan string, 10)     wg.Add(3)     go 快遞員(快遞柜)     go 張三(快遞柜)     go 李四(快遞柜)     wg.Wait() }

總結

上述講述了Go語言并發如何和channel配合使用,畢竟我們一般的任務都不是單獨運行的,都是互相配合的。

感謝各位的閱讀,以上就是“Go語言基礎并發channel”的內容了,經過本文的學習后,相信大家對Go語言基礎并發channel這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

延川县| 禄劝| 沧州市| 尼玛县| 龙口市| 深水埗区| 开鲁县| 宁城县| 周宁县| 广宗县| 嘉峪关市| 玉溪市| 东至县| 棋牌| 三门县| 福贡县| 凌源市| 广州市| 黄大仙区| 龙岩市| 都昌县| 英山县| 高陵县| 云林县| 台湾省| 子长县| 开远市| 衡阳县| 平度市| 德兴市| 阳曲县| 丰宁| 博白县| 祁阳县| 新昌县| 邯郸县| 收藏| 田林县| 临安市| 思南县| 肇源县|