<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
其實無論是原子函數還是共用鎖都是通過共用記憶體的方式進行的同步、效率一般不高,而Go語言中則使用了通道,它是一種通過傳遞資訊的方式進行資料同步,通過傳送和接收需要共用的資源,在goroutine 之間做同步。可以把通道看作是Goroutine之間的橋樑。
例1:建立一個通道
// 無緩衝的整型通道 unbuffered := make(chan int) // 有緩衝的字串通道 buffered := make(chan string, 10)
通道分為有緩衝和無緩衝的通道。
建立一個Channel的關鍵點:1.使用make建立 2.使用chan來告訴make我要建立的是通道 3.要告訴通道我要建立什麼型別的通道。
例2:向通道傳送值和接受值
// 有緩衝的字串通道 buffered := make(chan string, 10) // 通過通道傳送一個字串 buffered <- "Gopher" // 從通道接收一個字串 value := <-buffered
這個例子中建立了一個string型別的Channel,並向通道內傳遞了一個“Gopher”字串,這裡是通過<-進行傳入的,然後通過<-這個方式把值放到value當中。
這裡我的理解 <-就好比是一個賦值符號,無論是把值傳遞到Channel中,還是把Channel中的值傳出來,都是將右邊的值給左邊
由上面的例如1,可以看到Channel也是有多種的,分為無緩衝通道和有緩衝通道,下面就簡單總結一下兩種型別的通道。
無緩衝的通道(unbuffered channel)是指在接收前沒有能力儲存任何值的通道。這種型別的通道要求傳送goroutine 和接收goroutine 同時準備好,才能完成傳送和接收操作。
上面的圖很好的解釋了通道和Goroutine的關係
下面這個程式,模擬了兩個人打網球,很好的模擬了兩個協程間通過channel進行資料交換
package ChannelDemo import ( "fmt" "math/rand" "sync" "time" ) var wg sync.WaitGroup func init() { rand.Seed(time.Now().UnixNano()) } func PlayTennis() { court := make(chan int) wg.Add(2) //啟動了兩個協程,一個納達爾一個德約科維奇 go player("納達爾", court) go player("德約科維奇", court) //將1放到通道中,模擬開球 court <- 1 wg.Wait() } func player(name string, court chan int) { defer wg.Done() for { // 將資料從通道中取出 ball, ok := <-court if !ok { fmt.Printf("選手 %s 勝利n", name) return } //獲取一個隨機值,如果可以整除13,就讓一個人沒有擊中,進而關閉整個通道 n := rand.Intn(100) if n%13 == 0 { fmt.Printf("選手 %s 沒接到n", name) close(court) return } //如果擊中球,就將擊球的數量+1,放回通道中 fmt.Printf("選手 %s 擊中 %dn", name, ball) ball++ court <- ball } }
執行結果(每次會有變化):
選手 納達爾 擊中 1
選手 德約科維奇 擊中 2
選手 納達爾 擊中 3
選手 德約科維奇 擊中 4
選手 納達爾 擊中 5
選手 德約科維奇 擊中 6
選手 納達爾 擊中 7
選手 德約科維奇 擊中 8
選手 納達爾 沒接到
選手 德約科維奇 勝利
ok 標誌是否為false。如果這個值是false,表示通道已經被關閉,遊戲結束。
下面這個例子,模擬裡一個接力賽,也就是協程之間的傳遞的另一種形式
package ChannelDemo import ( "fmt" "sync" "time" ) var runnerWg sync.WaitGroup func Running() { //建立一個「接力棒」,也就是通道 baton := make(chan int) runnerWg.Add(1) //建立第一個跑步走 go Runner(baton) //開始跑 baton <- 1 runnerWg.Wait() } func Runner(baton chan int) { var newRunner int //選手接過接力棒 runner := <-baton fmt.Printf("第 %d 選手接棒 n", runner) //如果不是第四名選手,那麼說明比賽還在繼續 if runner != 4 { //建立一名新選手 newRunner = runner + 1 fmt.Printf("第 %d 準備接棒 n", newRunner) go Runner(baton) } //模擬跑步 time.Sleep(100 * time.Millisecond) //如果第四名跑完了,就結束 if runner == 4 { fmt.Printf("第 %d 結束賽跑 n", runner) runnerWg.Done() return } fmt.Printf("第 %d 選手和第 %d 選手交換了接力棒 n", runner, newRunner) //選手遞出接力棒 baton <- newRunner }
執行結果:
第 1 名選手接棒
第 2 名選手準備接棒
第 1 名選手將接力棒遞給第 2 名選手
第 2 名選手接棒
第 3 名選手準備接棒
第 2 名選手將接力棒遞給第 3 名選手
第 3 名選手接棒
第 4 名選手準備接棒
第 3 名選手將接力棒遞給第 4 名選手
第 4 名選手接棒
第 4 名選手衝線,比賽結束
我在看例子的過程中,其實遇到的問題在於,我沒有理解goroutine是怎麼進行交換的,我以為是goroutine有一個集合一樣的結構在通道外面等待取資料,這樣就存在我剛拿完再那的情況。就像下面這個圖顯示一樣
但是實際情況應該像下面
Go1寫入通道鎖住的Go1、Go2讀出進入通道鎖住Go2,只有Go1寫完Go2取完才能釋放,但是像上面第一個例子程式碼,讀出之後馬上就寫入,所以對於這樣的協程其實一直是鎖住的狀態。兩個協程就通過這種方式進行資料的傳遞。
到此這篇關於Go語言通道之無緩衝通道的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45