英文:
Golang concurrent array access
问题
在每个goroutine都使用指向相同底层数组的切片,但没有重叠的情况下,从多个goroutine访问同一个数组是安全的。
就像你提供的代码示例一样:
var arr [100]int
sliceA := arr[:50]
sliceB := arr[50:]
go WorkOn(sliceA)
go WorkOn(sliceB)
只要确保每个goroutine只操作自己的切片,而不会访问其他切片的元素,就可以安全地从多个goroutine访问同一个数组。这是因为切片本身包含了指向底层数组的指针和长度信息,每个goroutine都可以独立地操作自己的切片,而不会干扰其他goroutine。
需要注意的是,如果多个goroutine同时修改同一个切片的元素,可能会导致竞态条件和数据竞争问题。因此,在并发访问同一个切片时,需要采取适当的同步措施,例如使用互斥锁或通道来确保访问的原子性和一致性。
希望能帮到你!
英文:
Is it safe to access the same array from multiple goroutines, when every goroutine works on a slice, pointing to the same underlying array but without overlapping ?
Like:
var arr [100]int
sliceA := arr[:50]
sliceB := arr[50:]
go WorkOn(sliceA)
go WorkOn(sliceB)
Just imagine "WorkOn" would do something fancy.
答案1
得分: 10
只要你能保证这些区域不会重叠,就可以。
我所说的保证是:任何在sliceA
上工作的人,不应该允许执行sliceA = append(sliceA, a, b, c)
这样的操作。因为这样会导致它进入sliceB
的领域。
这里与之相关的是关于Go 1.2的一些文档:Go 1.2:
这涉及到一个新的语言元素:三索引切片:
> Go 1.2增加了在对现有数组或切片进行切片操作时,可以指定容量和长度的能力。切片操作通过描述已创建的数组或切片的连续部分来创建一个新的切片:
var array [10]int
slice := array[2:4]
> 切片的容量是切片可以容纳的最大元素数量,即使在重新切片后也是如此;它反映了底层数组的大小。在这个例子中,切片变量的容量是8。
> Go 1.2添加了新的语法,允许切片操作指定容量和长度。第二个冒号引入了容量值,它必须小于或等于源切片或数组的容量,根据起始位置进行调整。例如,
slice = array[2:4:7]
> 将切片的长度设置为之前的例子中的长度,但容量现在只有5个元素(7-2)。使用这个新的切片值无法访问原始数组的最后三个元素。
> 在这个三索引表示法中,缺失的第一个索引([:i:j])默认为零,但其他两个索引必须明确指定。未来的Go版本可能会为这些索引引入默认值。
> 更多详细信息请参阅设计文档。
英文:
As long as you can guarantee the areas won't overlap, it's fine.
By guarantee I mean: whomever works on sliceA
, should not be allowed to do sliceA = append(sliceA, a, b, c)
. Because then it'll start running into sliceB
's territory.
Relevant here, is some documentation for Go 1.2:
This concerns a new language element: 3-index slices:
> Go 1.2 adds the ability to specify the capacity as well as the length when using a slicing operation on an existing array or slice. A slicing operation creates a new slice by describing a contiguous section of an already-created array or slice:
var array [10]int
slice := array[2:4]
> The capacity of the slice is the maximum number of elements that the slice may hold, even after reslicing; it reflects the size of the underlying array. In this example, the capacity of the slice variable is 8.
> Go 1.2 adds new syntax to allow a slicing operation to specify the capacity as well as the length. A second colon introduces the capacity value, which must be less than or equal to the capacity of the source slice or array, adjusted for the origin. For instance,
slice = array[2:4:7]
> sets the slice to have the same length as in the earlier example but its capacity is now only 5 elements (7-2). It is impossible to use this new slice value to access the last three elements of the original array.
> In this three-index notation, a missing first index ([:i:j]) defaults to zero but the other two indices must always be specified explicitly. It is possible that future releases of Go may introduce default values for these indices.
> Further details are in the design document.
答案2
得分: 1
实际上,jimt的答案可能是错误的。这取决于...
例如,如果你正在使用一个[]uint8,那么像这样的操作:
p[2] = 5
实际上是这样的:
tmp = p[0..3] // 这是32位的
tmp[2] = 5
p[0..3] = tmp // 是的,这只是虚构的语法,但你会明白的
这是因为你的CPU是32位(甚至64位)。所以实际上这更高效,尽管看起来更复杂。
但是正如你所看到的,你正在写入p[0,1,3],尽管你只打算写入p[2]。这可能会导致一些有趣的错误需要调试!:)
如果你的数据是指向你的数据的指针,那么这个问题不应该发生,因为数组被保证存储在内存中,只要你的数据与本机指令集的长度一样长,就不会出现这个问题。
英文:
Actually jimt's answer MAY be wrong. It depends...
E.g. if you are using a []uint8, then a operation like
p[2] = 5
is essentially this
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
This is because your CPU is 32 (or even 64) bit. So that is actually more efficient although it seems more complex.
But as you can see, you are WRITING p[0,1,3] although you only intended to write to p[2]. This can create some fun bugs to debug!
If your data is e.g. pointers to your data then this issue should not occur as arrays are guaranteed to be stored in memory so that this problem doesn't occur as long as your data is as long as your native instruction set.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论