> Channel 通訊第一部分介紹了發送與接收操作之間最直觀的循序關聯性:> *向一個 Channel 中發送資料先於接收資料。*於是,我們能夠控制分佈於兩個 goroutine 中的操作的順序。```govar v intvar wg sync.WaitGroupwg.Add(2)ch := make(chan int)go func() { v = 1 ch <- 1 wg.Done()}()go func() { <-ch fmt.Println(v) wg.Done()}()wg.Wait()```(為了清晰,main 函數的定義和 import 語句被省略)操作的順序如下(*x* → *y* 代表 *x* 發生在 *y* 之前):`v = 1` → `ch <- 1` → `<-ch` → `fmt.Println(v)`除上述這條外,還有更多的順序規則,本篇將專註於 Channel。## 發送 接收![image](https://raw.githubusercontent.com/studygolang/gctt-images/master/sync-goroutine/part2-1.jpeg)除了上述規則,還有一條規則來補充它,這條規則說接收發生於發送完成之前:發送開始 → 接收 → 發送結束```govar v, w intvar wg sync.WaitGroupwg.Add(2)ch := make(chan int)go func() { v = 1 ch <- 1 fmt.Println(w) wg.Done()}()go func() { w = 2 <-ch fmt.Println(v) wg.Done()}()wg.Wait()```因為有了這條新的規則,更多的操作之間有了順序:`w = 2` → `<-ch` → 發送操作 `ch <- 1` 結束 → `fmt.Println(w)`通過保證賦值操作已經完成,我們就可以解決最初關於顯示變數 `v` 的問題。```gogo func() { v = 1 <-ch wg.Done()}()go func() { ch <- 1 fmt.Println(v) wg.Done()}()```現在第二個 goroutine 會往 channel 中發送資料,它需要等待第一個 goroutine 中的賦值操作 `v = 1` 完成。發送操作在對應的接收操作後才能完成。`v = 1` → `<-ch` → `ch <- 1` 結束 → `fmt.Println(v)`## 關閉 channel![image](https://raw.githubusercontent.com/studygolang/gctt-images/master/sync-goroutine/part2-2.jpeg)當 channel 被關閉時,接收操作會立即返回 channel 中的資料類型的[零值](https://golang.org/ref/spec#The_zero_value)。```goch := make(chan int)close(ch)fmt.Println(<-ch) // prints 0```>*關閉 channel 發生在從已關閉的 channel 中接收零值之前*把發送操作替換成調用內建函數 *close* 也可以解決我們最初的問題。```gogo func() { v = 1 close(ch) wg.Done()}()go func() { <-ch fmt.Println(v) wg.Done()}()```操作的順序是:`v = 1` → `close(ch)` → `<-ch` → `fmt.Println(v)`## 有緩衝的 channel到目前為止我們討論了無緩衝的 channel。有緩衝的 channel 在緩衝未滿時發送操作不會阻塞,在緩衝非空時接收操作也不會阻塞:```goch := make(chan int, 1)ch <- 1fmt.Println(<-ch)```上述程式並不會以死結告終,儘管在發送時並沒有準備好的接受者。對於有緩衝的 channel,目前為止提到的所有規則都是成立的,除了說接收發生在發送結束之前這一條。原因很簡單,(在緩衝未滿時),無需準備好的接受者,發送操作就可以結束。>*對於容量為 c 的 channel,第 k 個接收發生在第 (k+c) 個發送完成之前。*假定緩衝容量被設定為 3。前 3 個向 channel 發送資料的操作即使沒有相應的接收語句也可以返回。但是為了第 4 個發送操作完成,必須有至少一個接收操作完成。```govar v intvar wg sync.WaitGroupwg.Add(2)ch := make(chan int, 3)go func() { v = 1 <-ch wg.Done()}()go func() { ch <- 1 ch <- 1 ch <- 1 ch <- 1 fmt.Println(v) wg.Done()}()wg.Wait()```這一小段用有緩衝的 channel 解決了我們最初的問題。---點贊以協助別人發現這篇文章。如果你想得到新文章的更新,請關注我。## 資源- [goroutine 的同步(第一部分)](https://medium.com/golangspec/synchronized-goroutines-part-i-4fbcdd64a4ec)> Suppose that Go program starts two goroutines:> medium.com- [go 的記憶體模型 —— go 程式設計語言](https://golang.org/ref/mem)>The Go memory model specifies the conditions under which reads of a variable in one goroutine can be guaranteed to…> golang.org- [go 語言規範 —— go 程式設計語言](https://golang.org/ref/spec)>Go is a general-purpose language designed with systems programming in mind. It is strongly typed and garbage-collected…> golang.org*[保留部分著作權](http://creativecommons.org/licenses/by/4.0/)**[Golang](https://medium.com/tag/golang?source=post)**[Programming](https://medium.com/tag/programming?source=post)**[Concurrency](https://medium.com/tag/concurrency?source=post)**[Channels](https://medium.com/tag/channel?source=post)**[Synchronization](https://medium.com/tag/synchronization?source=post)***喜歡讀嗎?給 Michał Łowicki 一些掌聲吧。**簡單鼓勵下還是大喝采,根據你對這篇文章的喜歡程度鼓掌吧。
via: https://medium.com/golangspec/synchronized-goroutines-part-ii-b1130c815c9d
作者:Michał Łowicki 譯者:krystollia 校對:polaris1119
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
101 次點擊