我最近在学习 golang 的并发性,我在想一个程序生成一系列数字,然后将它们同时发送到三个 slice 。这是代码:
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)
}
}
输出如下:
length of bag1: 327643
length of bag2: 335630
length of bag3: 336725
total length: 999998
三个 slice 的总长度并不总是加起来等于发送给它们的数字计数。所以我的问题是:是什么导致了问题以及如何改进代码
最佳答案
您对 done
的使用 channel 根本不足以保证所有 3 sendToBag
goroutines 完全完成他们的工作。
虽然 channel 确实被 for n := range ch {
“完全耗尽”了声明之前 <-done
被执行时,您的代码中没有任何内容可以确保 <-done
在最后的 *bag = append(*bag, n)
之后 执行被执行,因此不能保证 len()
对包的调用将仅在 append()
之后执行电话。
使用 WaitGroup 而不是完成 channel 。
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()
}
关于go - 使用 channel 发送到多个 slice 时数据丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71284340/