讓你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ā)哦。