自己在網(wǎng)站開(kāi)發(fā)的客戶怎么聯(lián)系企業(yè)網(wǎng)站建設(shè)推廣
第二題:
創(chuàng)建一個(gè)生產(chǎn)器和接收器,再建立一個(gè)無(wú)緩沖的channel。生產(chǎn)器負(fù)責(zé)把數(shù)據(jù)放進(jìn)管道里,接收器負(fù)責(zé)把管道里面的數(shù)據(jù)打印出來(lái)。這里我們開(kāi)5個(gè)協(xié)程把數(shù)據(jù)打印出來(lái)。
直接上代碼!
package mainimport ("fmt"
)func receive(c <-chan int) {/*for v := range c {fmt.Println("received:", v)}*/for i := 0; i <= 1; i++ {go func() {for v := range c {fmt.Println(v)}}()}
}
func generator() <-chan int {c := make(chan int)for i := 0; i <= 9; i++ {go func(i int) {for j := 0; j <= 9; j++ {temp := i*100 + 20 + jc <- temp}close(c)}(i)}return c
}
func main() {c := generator()receive(c)
}
埋了個(gè)小坑,跑上面的代碼,在這里是不會(huì)有任何輸出的。
原因是main函數(shù)結(jié)束時(shí)程序就退出了,沒(méi)有給goroutine足夠運(yùn)行的時(shí)間來(lái)打印輸出。
整個(gè)流程是并發(fā)執(zhí)行的,main函數(shù)、generator的goroutine、receive的goroutine都是并發(fā)運(yùn)行。
但是問(wèn)題是main函數(shù)和generator很快就結(jié)束了,程序退出,receive的goroutine來(lái)不及打印數(shù)據(jù)。
解決方法就是讓main函數(shù)等一等receive的goroutine。我們?cè)趍ain函數(shù)中加上一句:
time.Sleep(time.Second * 5)
這時(shí)看到可以順利輸出了。
但是...
但是卻panic了。為什么呢?
因?yàn)間enerator()把消息發(fā)送到了關(guān)閉的管道。是因?yàn)樯善鱣oroutine和接收goroutine的生命周期沒(méi)有控制好導(dǎo)致的。
主要原因在于,接收的goroutine一旦從通道接收完所有的數(shù)據(jù)并退出,通道就會(huì)被關(guān)閉。
而此時(shí),生成器goroutine可能還在向這個(gè)通道發(fā)送數(shù)據(jù),于是產(chǎn)生了panic。
要避免這種情況,需要確保:
?
1、接收goroutine在最后一個(gè)生成器goroutine退出之前不能退出。
2、生成器goroutine在關(guān)閉通道之前,必須保證接收goroutine仍在運(yùn)行。
?
問(wèn)題出在生成器中close(c)這一行。這里每個(gè)goroutine都在自己完成后關(guān)閉了通道c。
按照程序邏輯,通道c應(yīng)該在最后一個(gè)goroutine完成時(shí)關(guān)閉一次,而不是每個(gè)goroutine都關(guān)閉。所以應(yīng)該只在主goroutine中關(guān)閉c。這里我們用WaitGroup來(lái)同步。
?
func generator() <-chan int {c := make(chan int) var wg sync.WaitGroupwg.Add(10) // 添加10個(gè)goroutinefor i := 0; i < 10; i++ {go func() {// 生成數(shù)據(jù) wg.Done() // goroutine結(jié)束}()} go func() {wg.Wait() // 等待所有g(shù)oroutine完成close(c) // 關(guān)閉通道,僅關(guān)閉一次 }()return c
}
?
順利輸出!!
?
?