我最近正在学习 golang 中的并发,我正在考虑一个程序,生成一系列数字,然后将它们同时发送到三个切片。这是代码:
func main() {
ch := make(chan int)
done := make(chan bool)
var bag1 []int
var bag2 []int
var bag3 []int
go func() {
for i := 0; i < 1000000; i++ {
ch <- i
}
close(ch)
done <- true
}()
go sendToBag(&bag1, ch)
go sendToBag(&bag2, ch)
go sendToBag(&bag3, ch)
<-done
len1 := (len(bag1))
len2 := (len(bag2))
len3 := (len(bag3))
fmt.Println("length of bag1:", len1)
fmt.Println("length of bag2:", len2)
fmt.Println("length of bag3:", len3)
fmt.Println("total length:", len1+len2+len3)
}
func sendToBag(bag *[]int, ch <-chan int) {
for n := range ch {
*bag = append(*bag, n)
}
}
Run Code Online (Sandbox Code Playgroud)
其输出如下所示:
length of bag1: 327643
length of bag2: 335630
length of bag3: 336725
total length: 999998
Run Code Online (Sandbox Code Playgroud)
三个切片的总长度并不总是等于发送给它们的数字计数。所以我的问题是:是什么导致了问题以及如何改进代码
您对通道的使用done
根本不足以保证所有 3 个sendToBag
goroutine 完全完成其工作。
虽然通道确实被执行之前的for n := range ch {
语句“完全耗尽” ,但代码中没有任何内容可以确保在执行final之后执行该语句,因此不能保证对包的调用将被执行仅在通话之后。 <-done
<-done
*bag = append(*bag, n)
len()
append()
使用等待组而不是完成通道。
func main() {
ch := make(chan int)
wg := sync.WaitGroup{}
var bag1 []int
var bag2 []int
var bag3 []int
go func() {
for i := 0; i < 1000000; i++ {
ch <- i
}
close(ch)
}()
wg.Add(3)
go sendToBag(&bag1, ch, &wg)
go sendToBag(&bag2, ch, &wg)
go sendToBag(&bag3, ch, &wg)
wg.Wait()
len1 := (len(bag1))
len2 := (len(bag2))
len3 := (len(bag3))
fmt.Println("length of bag1:", len1)
fmt.Println("length of bag2:", len2)
fmt.Println("length of bag3:", len3)
fmt.Println("total length:", len1+len2+len3)
}
func sendToBag(bag *[]int, ch <-chan int, wg *sync.WaitGroup) {
for n := range ch {
*bag = append(*bag, n)
}
wg.Done()
}
Run Code Online (Sandbox Code Playgroud)
https://go.dev/play/p/_wDgS5aS7bI