首先,存在数据竞争。
$ go run -race main.go
==================
WARNING: DATA RACE
Write at 0x00c0000b0018 by goroutine 11:
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:33 +0x11e
Previous write at 0x00c0000b0018 by goroutine 9:
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:33 +0x11e
Goroutine 11 (running) created at:
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:35 +0x211
Goroutine 9 (running) created at:
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:35 +0x211
==================
==================
WARNING: DATA RACE
Read at 0x00c0000b0010 by goroutine 12:
runtime.slicecopy()
/usr/lib/go-1.13/src/runtime/slice.go:197 +0x0
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:21 +0x39c
Previous write at 0x00c0000b0010 by goroutine 10:
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:33 +0x11e
Goroutine 12 (running) created at:
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:35 +0x211
Goroutine 10 (running) created at:
main.combinationUtil()
/home/leaf/spike/stackoverflow/concomb/main.go:40 +0x2dc
==================
这种数据竞争是由同时写入data 的底层数组引起的——这意味着data 的底层数组(因此data 的内容)在所有goroutine 上共享。这是不希望的。
在 Go 中,slice 的底层是一个切片头(参见reflect.SliceHeader),它将len、cap 和ptr 保存在三个字节中到底层数组。当您复制它时,它不会复制底层数组,而只是复制标头,因此底层数组是共享和竞争的 - 两者都不需要。
为避免这种情况,只需制作一个新副本即可。 (使用同步技术可以避免种族,但内容仍然是共享的)。然而,就时间和空间而言,仅此一项就是一项成本操作。这是否值得拥有并行的好处(如果有任何好处),是另一个话题,超出了这个答案的范围。
例如,
newdata := make([]int, r)
copy(newdata, data)
// current is included, put next at next location
newdata[index] = arr[i]
wg.Add(1)
go combinationUtil(ch, wg, arr, n, r, index+1, newdata, i+1)
// current is excluded, replace it with next (Note that
// i+1 is passed, but index is not changed)
wg.Add(1)
go combinationUtil(ch, wg, arr, n, r, index, newdata, i+1)
游乐场:https://play.golang.org/p/YebyCGapSMs
注意 1:这种简单的添加副本仅因为递归不依赖于 data (data[index:]) 的部分更改而起作用。否则,需要有newdata 到data 的备份。
注 2:正如我之前暗示的,我怀疑这种并行的效率如何。可以有其他的并行计算组合的方法,可以更好地利用并行计算的能力,但是需要完全不同的算法。不过,我不确定,所以如果有兴趣,你应该自己研究一下。