Golang并发数组访问

时间:2014-03-19 20:40:06

标签: concurrency synchronization go thread-safety locking

当每个goroutine在一个切片上工作,指向相同的底层数组但没有重叠时,从多个goroutine访问同一个数组是否安全?

像:

var arr [100]int
sliceA := arr[:50]
sliceB := arr[50:]

go WorkOn(sliceA)
go WorkOn(sliceB)

想象一下“WorkOn”会做点什么。

2 个答案:

答案 0 :(得分:8)

只要你能保证区域不会重叠,那就没关系。

保证我的意思是:任何人都可以使用sliceA可以sliceA = append(sliceA, a, b, c)。因为那时它将开始进入sliceB的领域。

此处相关,是Go 1.2的一些文档: 这涉及一个新的语言元素: 3索引切片

  

Go 1.2增加了在现有数组或切片上使用切片操作时指定容量和长度的功能。切片操作通过描述已创建的数组或切片的连续部分来创建新切片:

var array [10]int
slice := array[2:4]
  

切片的容量是切片可能保持的最大元素数,即使在重新切换之后也是如此;它反映了底层数组的大小。在此示例中,slice变量的容量为8。

     

Go 1.2添加了新语法,允许切片操作指定容量和长度。第二个冒号引入容量值,该值必须小于或等于源切片或阵列的容量,并根据原点进行调整。例如,

slice = array[2:4:7]
  

将切片设置为与前面示例中的长度相同,但其容量现在只有5个元素(7-2)。无法使用此新切片值访问原始数组的最后三个元素。

     

在这个三索引表示法中,缺少的第一个索引([:i:j])默认为零,但必须始终明确指定其他两个索引。未来的Go版本可能会为这些索引引入默认值。

     

详情请见design document

答案 1 :(得分:0)

实际上jimt的回答可能是错误的。这取决于...:)

例如如果您使用的是[] uint8,则类似

的操作
p[2] = 5

本质上是这个

tmp = p[0..3] // this is 32 bit
tmp[2] = 5
p[0..3] = tmp // yeah this is all fake syntax but you'll get it

这是因为您的CPU是32(甚至64)位。这样虽然看起来更复杂,但实际上效率更高。

但是正如您所看到的,尽管您只打算写p [2],但是您正在写p [0,1,3]。这可能会产生一些有趣的bug进行调试! :)

如果您的数据是指向您的数据的指针,则不会发生此问题,因为保证将数组存储在内存中,因此只要您的数据和您的本机指令集一样长,就不会发生此问题。