[英]Last value is missing when reading channel written in concurrent goroutines
我在Go中相当新,我希望异步运行几个任务,等待所有这些任务完成并将结果收集到一个切片中。
我正在阅读大量文档和示例,特别是Nathan LeClaire的帖子 ,并提出了一些接近我想做的事情(见下面的代码)。 机制很简单:
然而,结果显示9长度切片(值从0到8)和第10个值(应该是9)似乎缺失。 程序退出很好,我不知道发生了什么。 任何提示都表示赞赏。
这是一个与http://play.golang.org/p/HUFOZLmCto一起玩的代码示例:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
n := 10
c := make(chan int)
wg.Add(n)
for i := 0; i < n; i++ {
go func(val int) {
defer wg.Done()
fmt.Println("Sending value to channel: ", val)
c <- val
}(i)
}
var array []int
go func() {
for val := range c {
fmt.Println("Recieving from channel: ", val)
array = append(array, val)
}
}()
wg.Wait()
fmt.Println("Array: ", array)
}
这就是结果:
Sending value to channel: 0
Recieving from channel: 0
Sending value to channel: 1
Recieving from channel: 1
Sending value to channel: 2
Recieving from channel: 2
Sending value to channel: 3
Recieving from channel: 3
Sending value to channel: 4
Recieving from channel: 4
Sending value to channel: 5
Recieving from channel: 5
Sending value to channel: 6
Recieving from channel: 6
Sending value to channel: 7
Recieving from channel: 7
Sending value to channel: 8
Recieving from channel: 8
Sending value to channel: 9
Array: [0 1 2 3 4 5 6 7 8] // Note 9 is missing here
您在接收goroutine有机会接收并处理该值之前退出。 array
变量上还存在竞争条件,其中main
可能会尝试在append
操作期间打印数组。
请注意,即使使用无缓冲通道会在两个循环之间创建同步点,并保证接收循环具有wg.Done()
之前的值,也不能保证fmt.Println
和append
在main
继续之前发生。
安排这个的一种方法是将接收循环放在main中,然后在它自己的goroutine中等待关闭c
chan
:
go func() {
wg.Wait()
close(c)
}()
for val := range c {
fmt.Println("Recieving from channel: ", val)
array = append(array, val)
}
很简单。 在某些时候,所有值都被写入,waitGroup被释放并且goroutine正在填充sice。 由于waitGroup是释放的,因此可以在将通道排入切片之前进行打印。
要解决,请将wg.Done()移动到阅读器中,以防止在排水之前发生打印。
package main
import (
"fmt"
"sync"
)
func main() {
n := 10
c := make(chan int)
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < n; i++ {
go func(val int) {
fmt.Println("Sending value to channel: ", val)
c <- val
}(i)
}
var array []int
go func() {
for val := range c {
fmt.Println("Recieving from channel: ", val)
array = append(array, val)
wg.Done()
}
}()
wg.Wait()
fmt.Println("Array: ", array)
}
在操场上的例子
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.