简体   繁体   English

如何在 Golang 中并行生成组合

[英]How to Generate Combinations in Parallel in Golang

I'm trying to generate combinations (eg every 6 combo out of 10 numbers) in parallel using Golang.我正在尝试使用 Golang 并行生成组合(例如,10 个数字中的每 6 个组合)。

I have a solution that runs serially: Serial Code我有一个串行运行的解决方案:串行代码

For the case where the number of items(n) = 3 and the sample size (r) = 2, the output is:对于项目数 (n) = 3 和样本量 (r) = 2 的情况,输出为:

Got  [1 2]
Got  [1 3]
Got  [2 3]

Now I have tried parallelizing this and here is that code: Parallel Code .现在我尝试将其并行化,这是该代码: Parallel Code It doesn't work and I don't know why.它不起作用,我不知道为什么。 For the same problem the output is:对于同样的问题,输出是:

Put  [3 3] into the channel.
Got  [3 3] out of the channel.
Put  [3 3] into the channel.
Got  [3 3] out of the channel.
Put  [3 3] into the channel.
Got  [3 3] out of the channel.

Any help much appreciated.非常感谢任何帮助。

First, there is a data race.首先,存在数据竞赛。

$ 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
==================

This data race is caused by writing to the underlying array of data concurently - which means, underlying array of data (and thus the content of data ) is shared on all goroutine.这个数据争用是通过写的底层数组引起data concurently -这意味着,基本的阵列data (以及因此的内容data )对所有的goroutine共享。 That is undesired.这是不希望的。

In Go, what is under the hood of slice is a slice header (see reflect.SliceHeader ), it keeps in three bytes the len , cap and ptr to the underlying array.在Go,什么是引擎盖下slice是切片头(见reflect.SliceHeader ),它保持在三个字节lencapptr为基础数组。 When you copy it, it does not copy the underlying array, but rather only the header, so the underlying array is shared and raced - neither is desired.当您复制它时,它不会复制底层数组,而是只复制标头,因此底层数组是共享和竞争的 - 两者都不是需要的。

To avoid that, just make a new copy of it.为避免这种情况,只需制作一个新副本即可。 (using sync techniques may avoid race, but the content is still shared). (使用同步技术可以避免竞争,但内容仍然是共享的)。 However, that alone is a costing operation, both in terms of time and space.然而,就时间和空间而言,仅此一项就是成本计算。 Whether that will worth the benefit of having parellel (if there is any benefit), is another topic and out of scope of this answer.这是否值得拥有并行的好处(如果有任何好处),是另一个主题,超出了本答案的范围。

For example,例如,

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)

playground: https://play.golang.org/p/YebyCGapSMs游乐场: https : //play.golang.org/p/YebyCGapSMs

Note 1: This simple addition of a copy works only because that the recursion does not relies on change of part of data ( data[index:] ).注 1:这种简单的副本添加之所以有效,只是因为递归不依赖于部分datadata[index:] )的更改。 Otherwise, there needs to be a back-copy for newdata to data .否则,需要将newdata备份到data

Note 2: As I implied before, I doubt how efficient is this kind of parellel.注 2:正如我之前暗示的那样,我怀疑这种并行的效率如何。 There can be other ways of calculating combinations in parellel, which may utilize power of parellel calculation better, but requires quite different algorithms.可以有其他的并行计算组合的方法,这些方法可以更好地利用并行计算的能力,但需要完全不同的算法。 However, I am not certain of that, so you should do your own research if interested.但是,我不确定这一点,所以如果你有兴趣,你应该自己研究。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM