自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇文章帶你了解Go語(yǔ)言基礎(chǔ)之并發(fā)(channel)

開(kāi)發(fā) 前端
本篇繼續(xù)帶來(lái)Go語(yǔ)言并發(fā)基礎(chǔ),channel如何使用??纯碐o協(xié)程如何配合channel。

[[360253]]

 前言

Hi,大家好,我是碼農(nóng),星期八,本篇繼續(xù)帶來(lái)Go語(yǔ)言并發(fā)基礎(chǔ),channel如何使用。

看看Go協(xié)程如何配合channel。

為什么需要channel

channel在Go中,也叫做管道,是用來(lái)多線程之間共享數(shù)據(jù)的。

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

  • 共享內(nèi)存實(shí)現(xiàn)通訊。
  • 通過(guò)管道(channel)通訊(推薦)。

為啥子共享內(nèi)存通訊不太推薦?

示例代碼:多線程修改一個(gè)值。

函數(shù)

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

main

  1. var NUM = 100 
  2. var wg sync.WaitGroup 
  3.  
  4. func main() { 
  5.     for i := 0; i<100;i++  { 
  6.         wg.Add(1) 
  7.         go Calc() 
  8.     wg.Wait() 
  9.     fmt.Println(NUM) 

執(zhí)行結(jié)果


沒(méi)錯(cuò),是2,懵了吧,哈哈哈,理論應(yīng)該是0才對(duì)呀。

這是為啥?

這就是共享內(nèi)存不太推薦的原因,我們的代碼已經(jīng)是多線程了。

在第一個(gè)函數(shù)代碼中,第3行,NUM = NUM - 1。

如果多個(gè)線程同時(shí)執(zhí)行到這一行,并且沒(méi)有加鎖,就會(huì)出現(xiàn)數(shù)據(jù)錯(cuò)亂。

那該怎么做呢?

加鎖,加鎖可以保證某一段代碼只能被一個(gè)線程執(zhí)行,防止被爭(zhēng)搶。

代碼

  1. func Calc() { 
  2.     defer wg.Done() 
  3.     mutex.Lock() 
  4.     NUM = NUM - 1 
  5.     mutex.Unlock() 

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

執(zhí)行結(jié)果


這次真的是0的,不管執(zhí)行幾次。

但是會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,如果采用這種方式,需要常常注意競(jìng)爭(zhēng)問(wèn)題。

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

channel語(yǔ)法

channel格式

  1. var 變量名 chan 類型 
  2. 例如 
  3. var x1 chan int //x1管道里面只能存int類型數(shù)據(jù) 
  4. var x2 chan string //x2管道里面只能存字符串類型數(shù)據(jù) 

注意


定義管道時(shí),chan int是一個(gè)整體,別搞錯(cuò)了各位。

創(chuàng)建channel

創(chuàng)建channel,只能通過(guò)make創(chuàng)建。

格式

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

channel操作

創(chuàng)建一個(gè)管道。

  1. ch = make(chan int,10) 

channel是一個(gè)管道,就像一個(gè)管子。

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

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

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

關(guān)閉管子close(ch)。

注意:channel是先入先出結(jié)構(gòu),就像這樣。

 

注意事項(xiàng):

  • 如果通道塞滿了,再塞 會(huì)阻塞住。
  • 如果通道關(guān)閉了,是不能再塞值了,否則會(huì)panic。
  • 即使通道關(guān)閉了,依然可以取值,直到將管道的值取完,取完后得到的是對(duì)應(yīng)類型零值。
  • 管道不能重復(fù)關(guān)閉,重復(fù)關(guān)閉會(huì)panic。

無(wú)緩沖管道

無(wú)緩沖就是這個(gè)管道沒(méi)有長(zhǎng)度,就像這樣。

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


示例代碼

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.  
  6. //模擬張三 
  7. func 張三(x chan string) { 
  8.     var a = <-x 
  9.     fmt.Println(a) 
  10.  
  11. func main() { 
  12.     //通道沒(méi)有長(zhǎng)度,就是無(wú)緩沖通道 
  13.     var x = make(chan string) 
  14.     go 張三(x) 
  15.     x <- "張三的快遞" 
  16.     fmt.Println("張三快遞交付成功"

第16行寫(xiě)入一個(gè)值,同理,張三就要等著去接,如果沒(méi)人接,那就完了。

假設(shè)注釋第9行代碼。

直接報(bào)錯(cuò),all goroutines are asleep - deadlock!,這句話的意思是所有的協(xié)程都睡著了,死鎖

無(wú)緩沖說(shuō)明通道長(zhǎng)度為0,發(fā)送一個(gè)值會(huì)阻塞住。

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

有緩沖管道

 

 

這個(gè)就簡(jiǎn)單啦,多了一個(gè)快遞柜,快遞員直接將快遞仍快遞柜就行了。

示例代碼

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "sync" 
  6.  
  7. var wg sync.WaitGroup 
  8.  
  9. //快遞員,快遞員放10個(gè)快遞 
  10. func 快遞員(kuaidigui chan string) { 
  11.     defer wg.Done() 
  12.     for i := 0; i < 10; i++ { 
  13.         fmt.Println("快遞員放入了第",i,"快遞"
  14.         kuaidigui <- fmt.Sprintf("第%d個(gè)快遞", i) 
  15.     //放完快遞就關(guān)閉了通道 
  16.     close(kuaidigui) 
  17.  
  18. //張三,拿走3個(gè)快遞 
  19. func 張三(kuaidigui chan string) { 
  20.     defer wg.Done() 
  21.     for i := 0; i < 3; i++ { 
  22.         fmt.Println("張三拿走" + <-kuaidigui) 
  23. //李四拿走7個(gè)快遞 
  24. func 李四(kuaidigui chan string) { 
  25.     defer wg.Done() 
  26.     for i := 0; i < 7; i++ { 
  27.         fmt.Println("李四拿走" + <-kuaidigui) 
  28. func main() { 
  29.     //快遞柜,10個(gè)大小 
  30.     var 快遞柜 = make(chan string, 10) 
  31.     wg.Add(3) 
  32.     go 快遞員(快遞柜) 
  33.     go 張三(快遞柜) 
  34.     go 李四(快遞柜) 
  35.     wg.Wait() 

執(zhí)行結(jié)果 

 

遍歷channel兩種方式

代碼

  1. func main() { 
  2.     //快遞柜,10個(gè)大小 
  3.     var ch = make(chan int, 10) 
  4.     //向管道中發(fā)送值 
  5.     for i := 0; i < 10; i++ { 
  6.         ch <- i 
  7.     //方式一取值 
  8.     //for { 
  9.     //i, ok := <-ch 
  10.     ////取完值ok就是false 
  11.     //if !ok { 
  12.     //      //結(jié)束循環(huán) 
  13.     //      break 
  14.     //} 
  15.     //fmt.Println(i) 
  16.     //} 
  17.     //方式二取值 
  18.     for i:=range ch{ 
  19.         fmt.Println(i) 

執(zhí)行結(jié)果


報(bào)錯(cuò)是因?yàn)槲以趍ain中完成了發(fā)送值和取值兩個(gè)操作,所以會(huì)出現(xiàn)上述問(wèn)題,但是結(jié)果是沒(méi)有錯(cuò)的。

單向通道

我們知道通道是可以發(fā)送值和取值的,但是某些場(chǎng)景為了安全起見(jiàn),理論來(lái)說(shuō)只能取值,后者只能發(fā)送值。

單向通道通常只在函數(shù)參數(shù)中體現(xiàn)。

  • 形參 chan<- chan類型只寫(xiě)。
  • 形參 <-chan chan類型只讀。

修改上述快遞員代碼。

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "sync" 
  6.  
  7. var wg sync.WaitGroup 
  8.  
  9. //快遞員,快遞員放10個(gè)快遞,只寫(xiě) chan<- string 
  10. func 快遞員(kuaidigui chan<- string) { 
  11.     defer wg.Done() 
  12.     for i := 0; i < 10; i++ { 
  13.         fmt.Println("快遞員放入了第", i, "快遞"
  14.         kuaidigui <- fmt.Sprintf("第%d個(gè)快遞", i) 
  15.     //放完快遞就關(guān)閉了通道 
  16.     close(kuaidigui) 
  17.  
  18. //張三,拿走3個(gè)快遞,只讀<-chan string 
  19. func 張三(kuaidigui <-chan string) { 
  20.     defer wg.Done() 
  21.     for i := 0; i < 3; i++ { 
  22.         fmt.Println("張三拿走" + <-kuaidigui) 
  23.  
  24. //李四拿走7個(gè)快遞 
  25. func 李四(kuaidigui <-chan string) { 
  26.     defer wg.Done() 
  27.     for i := 0; i < 7; i++ { 
  28.         fmt.Println("李四拿走" + <-kuaidigui) 
  29. func main() { 
  30.     //快遞柜,10個(gè)大小 
  31.     var 快遞柜 = make(chan string, 10) 
  32.     wg.Add(3) 
  33.     go 快遞員(快遞柜) 
  34.     go 張三(快遞柜) 
  35.     go 李四(快遞柜) 
  36.     wg.Wait() 

總結(jié)

上述講述了Go語(yǔ)言并發(fā)如何和channel配合使用,畢竟我們一般的任務(wù)都不是單獨(dú)運(yùn)行的,都是互相配合的。

我們講述了如何創(chuàng)建channel,如何使用channel,有緩沖管道和無(wú)緩沖管道區(qū)別,并且拒了一個(gè)快遞員例子來(lái)展示協(xié)程和channel如何配合,最后用單向通道又加固了一下代碼。

我的代碼中使用了中文命名變量名是為了好看,實(shí)際開(kāi)發(fā)中千萬(wàn)不要這樣!!!

上述代碼一定要敲一下,如果在操作過(guò)程中有任何問(wèn)題,記得下面留言,我們看到會(huì)第一時(shí)間解決問(wèn)題。

不積跬步無(wú)以至千里,不積小流無(wú)以成江海,給自己一個(gè)成長(zhǎng)的時(shí)間

 

責(zé)任編輯:姜華 來(lái)源: Go語(yǔ)言進(jìn)階學(xué)習(xí)
相關(guān)推薦

2020-10-22 08:33:22

Go語(yǔ)言

2020-11-11 10:52:54

Go語(yǔ)言C語(yǔ)言

2020-11-05 09:58:16

Go語(yǔ)言Map

2022-02-16 10:03:06

對(duì)象接口代碼

2020-12-23 08:39:11

Go語(yǔ)言基礎(chǔ)技術(shù)

2020-12-07 05:59:02

語(yǔ)言Go接口

2021-10-30 10:43:04

語(yǔ)言Go函數(shù)

2021-11-03 10:02:07

Go基礎(chǔ)函數(shù)

2022-04-27 10:01:43

切片Go封裝

2020-12-30 09:04:32

Go語(yǔ)言TCPUDP

2020-10-25 07:33:13

Go語(yǔ)言

2020-12-09 09:59:32

Go語(yǔ)言技術(shù)

2020-10-23 08:38:19

Go語(yǔ)言

2021-10-09 07:10:31

Go語(yǔ)言基礎(chǔ)

2020-10-22 11:15:47

Go語(yǔ)言變量

2021-10-16 10:17:51

Go語(yǔ)言數(shù)據(jù)類型

2021-09-29 10:00:07

Go語(yǔ)言基礎(chǔ)

2021-10-13 10:00:52

Go語(yǔ)言基礎(chǔ)

2021-01-13 08:40:04

Go語(yǔ)言文件操作

2021-02-20 10:06:14

語(yǔ)言文件操作
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)