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

标签 go concurrency slice goroutine

我有一个包含要完成的工作的 slice ,以及一个包含所有完成后的结果的 slice 。以下是我的大致流程示意图:

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 都仅限于 slice 中自己的索引,这是预先分配的。

我想另一种方法是通过 channel 收集结果,但由于结果的顺序很重要,这似乎相当简单。以这种方式写入 slice 元素是否安全?

最佳答案

规则很简单:如果多个 goroutine 访问一个 variable并发,且至少有一次访问是写,则需要同步。

您的示例没有违反此规则。你不写 slice value( slice 头),你只读取它(隐含地,当你索引它时)。

你不读取 slice 元素,你只修改 slice 元素。并且每个 goroutine 只修改一个 不同指定的 slice 元素。而且由于每个 slice 元素都有自己的地址(自己的内存空间),它们就像不同的变量。这在 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.

必须记住的是,如果没有同步,您将无法从 results slice 中读取结果。您在示例中使用的 WaitGroup 是足够的同步。一旦 wg.Wait() 返回,您就可以读取 slice ,因为这只能发生在所有调用 wg.Done() 的工作 goroutine 之后,并且没有一个工作goroutine 在调用 wg.Done() 之后修改元素。

例如,这是检查/处理结果的有效(安全)方式:

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

但如果你试图在 wg.Wait() 之前访问 results 的元素,那就是数据竞争:

// This is data race! Goroutines might still run and modify elements of results!
fmt.Println(results)
wg.Wait()

关于go - 我可以同时编写不同的 slice 元素吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49879322/

相关文章:

arrays - 在函数参数中接收任何数组类型

c++ - 使用 pthread 处理数组/vector 的各个部分

python - 访问 3D numpy 数组的切片

dictionary - 具有固定大小的 Golang 并发访问映射/数组

go - 评估/执行 Golang 代码/表达式,如 js 的 eval()

mongodb - mgo 有序排序聚合

java - 并发访问 @Lock(LockType.WRITE) 方法

java - 如何使用 jToggleButton 停止 Java 中用于使用 WatchService 监视文件夹中文件的以下类型的线程

arrays - 如何在子 slice 中拆分 Go 中的 slice

hash - 如何在 Go 中生成字符串的哈希数?