Go中按次序交替打印1212...,你知道它背后的設(shè)計(jì)模式嗎

讓你goroutine交替打印1212...【公粽號(hào):堆棧future】
原文
首先這道題看似是兩個(gè)goroutine交替打印,實(shí)則是有很多細(xì)節(jié)需要考慮,而且背后的設(shè)計(jì)模式就是生產(chǎn)者消費(fèi)者模式。

代碼演示下簡(jiǎn)單的生產(chǎn)者消費(fèi)者模式:

package main

import "fmt"

func main() {
done := make(chan bool) //控制結(jié)束退出的信號(hào)
ch := make(chan int) //chan通信 控制同步阻塞的

go func() {
for i:=1; i<=2; i++ {
//生產(chǎn)
ch <- 0
fmt.Println("1")
}

//發(fā)送結(jié)束之后退出
done <- true
}()

go func() {
for i:=1; i<=2; i++ {
//消費(fèi)
<- ch
fmt.Println("2")
}
}()
<-done
}

輸出:
1
1
2
2
但是題目是讓兩個(gè)goroutine交替輸出1212...而且還必須保證次序,比如A goroutine是永遠(yuǎn)打印1,B goroutine永遠(yuǎn)打印2 這樣循環(huán)2次,輸出結(jié)果應(yīng)該是1212。

那么為什么上面的代碼輸出是1122呢?因?yàn)槲覀兛刂屏碎_(kāi)始的次序,但是并沒(méi)有控制結(jié)束的次序,發(fā)生了并發(fā)不安全的情況。

當(dāng)然你不能說(shuō)這種方式就不適合別的場(chǎng)景,比如交替打印奇偶數(shù),就增加一個(gè)條件判斷就行:

package main

import "fmt"

func main() {
done := make(chan bool) //控制結(jié)束退出的信號(hào)
ch := make(chan int) //chan通信 控制同步阻塞的

go func() {
for i:=1; i<=5; i++ {
//生產(chǎn)
ch <- 0
if i % 2 == 0 {
fmt.Println("A ", i)
}
}

//發(fā)送結(jié)束之后退出
done <- true
}()

go func() {
for i:=1; i<=5; i++ {
//消費(fèi)
<- ch
if i % 2 != 0 {
fmt.Println("B ", i)
}
}
}()
<-done
}

輸出:
B 1
A 2
B 3
A 4
B永遠(yuǎn)輸出奇數(shù),A永遠(yuǎn)輸出偶數(shù),它們交替打印。

好了言歸正傳,那我們?nèi)绾螌?xiě)出并發(fā)安全的生產(chǎn)者消費(fèi)者代碼呢?我們用首尾兩個(gè)chan交替釋放控制權(quán)就可以解決這個(gè)問(wèn)題,請(qǐng)看代碼:

package main

import "fmt"

func main() {
done := make(chan bool) //控制結(jié)束退出的信號(hào)
chStart := make(chan int) //chan通信 控制起始同步阻塞的
chEnd := make(chan int) //chan通信 控制結(jié)尾同步阻塞的

go func() {
for i:=1; i<=2; i++ {
//生產(chǎn) 控制起始
chStart <- 0
fmt.Println("A ", 1)
//暫停 等待結(jié)尾信號(hào)
<-chEnd
}

//發(fā)送結(jié)束之后退出
done <- true
}()

go func() {
for i:=1; i<=2; i++ {
//消費(fèi) 結(jié)束起始
<- chStart
fmt.Println("B ", 2)

//發(fā)送結(jié)尾信號(hào)
chEnd <- 0
}
}()

//阻塞等待退出信號(hào)
<-done
}

輸出:
A 1
B 2
A 1
B 2
現(xiàn)在可以看出來(lái),輸出的結(jié)果是正確的。為什么這么操作呢?就是當(dāng)生產(chǎn)者生產(chǎn)之后把自己阻塞,等待消費(fèi)者消費(fèi),消費(fèi)者消費(fèi)完成之后發(fā)送信號(hào)喚醒生產(chǎn)者繼續(xù)生產(chǎn),而消費(fèi)者自己又被阻塞等生產(chǎn)者喚醒,其實(shí)這就是典型的生產(chǎn)者消費(fèi)者模式。

小結(jié)

用兩個(gè)chan實(shí)現(xiàn)按次序交替非常有意思,它背后的設(shè)計(jì)模式生產(chǎn)者消費(fèi)者模式,大家可以在項(xiàng)目中使用起來(lái),如果你覺(jué)得這篇文章對(duì)你有幫助,歡迎關(guān)注點(diǎn)贊轉(zhuǎn)發(fā)哦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容