Go無緩沖通道(同步通道)的實現(xiàn)
無緩沖的通道又稱為阻塞的通道,我們來看一下如下代碼片段。
package main import "fmt" func main() { ch := make(chan int) ch <- 1 fmt.Println("發(fā)送成功") }
上面這段代碼能夠通過編譯,但是執(zhí)行的時候會出現(xiàn)以下錯誤:
deadlock表示我們程序中的 goroutine 都被掛起導致程序死鎖了。為什么會出現(xiàn)deadlock錯誤呢?
因為我們使用ch := make(chan int)創(chuàng)建的是無緩沖的通道,無緩沖的通道只有在有接收方能夠接收值的時候才能發(fā)送成功,否則會一直處于等待發(fā)送的階段。
上面的代碼會阻塞在ch <- 1這一行代碼形成死鎖,那如何解決這個問題呢?
其中一種可行的方法是創(chuàng)建一個 goroutine 去接收值,例如:
package main import ( "sync" ) func main() { var wg sync.WaitGroup wg.Add(1) ch := make(chan int) ch <- 1 go func() { defer wg.Done() v := <-ch fmt.Println(v) }() close(ch) wg.Wait() }
我們已經(jīng)開了一個go協(xié)程從管道中讀去數(shù)據(jù)了,為什么還會報錯呢?
因為當程序執(zhí)行到 ch <- 1時,進已經(jīng)發(fā)生了阻塞,下面的go協(xié)程還沒有來得及啟動。
go的channel在執(zhí)行寫入時會先檢查在此之前有沒有讀取數(shù)據(jù)的一方已經(jīng)存在,在讀取時會先檢查在此之前有沒有寫入方已經(jīng)存在。
當我們將讀的協(xié)程先啟動,再寫入,就可以了,代碼如下:
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(1) ch := make(chan int) go func() { defer wg.Done() v := <-ch fmt.Println(v) }() ch <- 1 close(ch) wg.Wait() }
同理,如果對一個無緩沖通道執(zhí)行接收操作時,沒有任何向通道中發(fā)送值的操作那么也會導致接收操作阻塞。
package main import "fmt" func main() { ch := make(chan int) <-ch fmt.Println("接收成功") }
其中一種可行的方法是創(chuàng)建一個 goroutine 去寫入值,例如:
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(1) ch := make(chan int) v := <-ch go func() { defer wg.Done() ch <- 1 }() fmt.Println(v) close(ch) wg.Wait() }
同理,因為當程序執(zhí)行到 v := <-ch 時,進已經(jīng)發(fā)生了阻塞,下面的go協(xié)程還沒有來得及啟動。
當我們將寫的協(xié)程先啟動,再讀取,就可以了,代碼如下:
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(1) ch := make(chan int) go func() { defer wg.Done() ch <- 1 }() v := <-ch fmt.Println(v) close(ch) wg.Wait() }
使用無緩沖通道進行通信將導致發(fā)送和接收的 goroutine 同步化。因此,無緩沖通道也被稱為同步通道。
同步:兩個goroutine1(寫入方)、goroutine2(讀取方),
goroutine1先執(zhí)行,如果想要再次發(fā)送(寫入)數(shù)據(jù)的話,必須等待goroutine2將channel中的數(shù)據(jù)取出來(讀取)之后,才能再次發(fā)送。
goroutine2先執(zhí)行,如果想要再次接收數(shù)據(jù)的話,必須等待goroutine1再次向channel中寫入數(shù)據(jù)之后,才能再次接收。
執(zhí)行順序(goroutine1,goroutine2,goroutine1,goroutine2…)goroutine1和goroutine2交替執(zhí)行。
示例演示:使用一個無緩沖channel和兩個goroutine實現(xiàn)交替打印一個字符串。
package main import "fmt" func main() { ch := make(chan int) str := "hello, world" go func() { for { index, ok := <-ch if !ok { break } if index >= len(str) { close(ch) break } fmt.Printf("Goroutine1 : %c\n", str[index]) ch <- index + 1 } }() ch <- 0 for { index, ok := <-ch if !ok { break } if index >= len(str) { close(ch) break } fmt.Printf("Goroutine1 : %c\n", str[index]) ch <- index + 1 } }
到此這篇關于Go無緩沖通道(同步通道)的實現(xiàn)的文章就介紹到這了,更多相關Go無緩沖通道內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mac下Vs code配置Go語言環(huán)境的詳細過程
這篇文章給大家介紹Mac下Vs code配置Go語言環(huán)境的詳細過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-07-07