我有一个包含要完成的工作的切片,还有一个包含完成所有操作后的结果的切片。下面是我的大致流程的一个草图:
var results = make([]Result, len(jobs))
wg := sync.WaitGroup{}
for i, job := range jobs {
wg.Add(1)
go func(i int, j job) {
defer wg.Done()
var r Result = doWork(j)
results[i] = r
}(i, job)
}
wg.Wait()
// Use results
它似乎有效,但我还没有彻底测试它,不确定这样做是否安全。一般来说,让多个 goroutine 写入数据我感觉不太好anything,但在这种情况下,每个 goroutine 仅限于切片中自己的索引,该索引是预先分配的。
我想另一种选择是通过渠道收集结果,但由于结果的顺序很重要,这看起来相当简单。以这种方式写入切片元素安全吗?
规则很简单:如果多个 goroutine 访问一个variable并发,且至少有一次访问是写,则需要同步。
你的例子并没有违反这个规则。你不写切片value(切片头),您只读取它(隐式地,当您索引它时)。
你不读切片elements,您只需修改切片元素。每个 goroutine 只修改一个,不同的, 指定的切片元素。由于每个切片元素都有自己的地址(自己的内存空间),因此它们就像不同的变量。这涵盖在规格: 变量:
结构化的的变量array, slice, and struct类型的元素和字段可能是已解决单独。每个这样的元素就像一个变量。
必须记住的是,您无法从results
没有同步的切片。您在示例中使用的 waitgroup 已经足够同步。您可以读取该切片一次wg.Wait()
返回,因为这只能在所有工作 goroutine 调用之后发生wg.Done()
,并且没有一个工作协程在调用后修改元素wg.Done()
.
例如,这是一个有效的 (safe) 检查/处理结果的方法:
wg.Wait()
// Safe to read results after the above synchronization point:
fmt.Println(results)
但是如果您尝试访问以下元素results
before wg.Wait()
,这是一场数据竞赛:
// This is data race! Goroutines might still run and modify elements of results!
fmt.Println(results)
wg.Wait()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)