douzhuang2016 2018-04-17 13:23
浏览 76
已采纳

我可以同时写不同的slice元素吗

I have a slice that contains work to be done, and a slice that will contain the results when everything is done. The following is a sketch of my general process:

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

It seems to work, but I have not tested it thoroughly and am not sure if it is safe to do. Generally I would not feel good letting multiple goroutines write to anything, but in this case, each goroutine is limited to its own index in the slice, which is pre-allocated.

I suppose the alternative is collecting results via a channel, but since order of results matters, this seemed rather simple. Is it safe to write into slice elements this way?

  • 写回答

2条回答 默认 最新

  • duanchifo2866 2018-04-17 13:29
    关注

    The rule is simple: if multiple goroutines access a variable concurrently, and at least one of the accesses is a write, then synchronization is required.

    Your example does not violate this rule. You don't write the slice value (the slice header), you only read it (implicitly, when you index it).

    You don't read the slice elements, you only modify the slice elements. And each goroutine only modifies a single, different, designated slice element. And since each slice element has its own address (own memory space), they are like distinct variables. This is covered in Spec: Variables:

    Structured variables of array, slice, and struct types have elements and fields that may be addressed individually. Each such element acts like a variable.

    What must be kept in mind is that you can't read the results from the results slice without synchronization. And the waitgroup you used in your example is a sufficient synchronization. You are allowed to read the slice once wg.Wait() returns, because that can only happen after all worker goroutines called wg.Done(), and none of the worker goroutines modify the elements after they called wg.Done().

    For example, this is a valid (safe) way to check / process the results:

    wg.Wait()
    // Safe to read results after the above synchronization point:
    fmt.Println(results)
    

    But if you would try to access the elements of results before wg.Wait(), that's a data race:

    // This is data race! Goroutines might still run and modify elements of results!
    fmt.Println(results)
    wg.Wait()
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改
  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上