当每个goroutine在一个切片上工作,指向相同的底层数组但没有重叠时,从多个goroutine访问同一个数组是否安全?
像:
var arr [100]int
sliceA := arr[:50]
sliceB := arr[50:]
go WorkOn(sliceA)
go WorkOn(sliceB)
想象一下“WorkOn”会做点什么。
答案 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进行调试! :)
如果您的数据是指向您的数据的指针,则不会发生此问题,因为保证将数组存储在内存中,因此只要您的数据和您的本机指令集一样长,就不会发生此问题。