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()
}

我們已經開了一個go協(xié)程從管道中讀去數(shù)據了,為什么還會報錯呢?
因為當程序執(zhí)行到 ch <- 1時,進已經發(fā)生了阻塞,下面的go協(xié)程還沒有來得及啟動。
go的channel在執(zhí)行寫入時會先檢查在此之前有沒有讀取數(shù)據的一方已經存在,在讀取時會先檢查在此之前有沒有寫入方已經存在。
當我們將讀的協(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 時,進已經發(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ù)據的話,必須等待goroutine2將channel中的數(shù)據取出來(讀取)之后,才能再次發(fā)送。
goroutine2先執(zhí)行,如果想要再次接收數(shù)據的話,必須等待goroutine1再次向channel中寫入數(shù)據之后,才能再次接收。
執(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無緩沖通道內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
B站新一代 golang規(guī)則引擎gengine基礎語法
這篇文章主要為大家介紹了B站新一代 golang規(guī)則引擎gengine基礎語法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12

