f# - F# 并行序列中的奇怪行为

标签 f# task-parallel-library

我编写了以下代码来生成某些数字的所有可能组合:

let allCombinations (counts:int[]) = 
   let currentPositions = Array.create (counts.Length) 0     
   let idx = ref (counts.Length-1) 
   seq{
       while currentPositions.[0]<counts.[0] do                        
           yield currentPositions           
           currentPositions.[!idx]<-currentPositions.[!idx]+1         
           while currentPositions.[!idx] >= counts.[!idx] && !idx>=1 do
               currentPositions.[!idx]<-0
               idx:=!idx-1
               currentPositions.[!idx]<-currentPositions.[!idx]+1               
           idx:=counts.Length-1            
   } 

我正在程序的其他部分使用该序列,如下所示:

allCombinations counts |> Seq.map (fun idx -> buildGuess n digitsPerPos idx) ...

到目前为止一切顺利。程序按预期运行并生成组合。对于输入 [|2;2;2|],它生成八个值:

 [|0; 0; 0|]
 [|0; 0; 1|]
 [|0; 1; 0|]
 [|0; 1; 1|]
 [|1; 0; 0|]
 [|1; 0; 1|]
 [|1; 1; 0|]
 [|1; 1; 1|]

但是,当我使用 PSeq 并行化生成的序列时,要使用的所有值都会更改为 [|2;0;0|],这是上面 while 循环中 currentPositions 数组的最后一个值。

如果我使用

yield (currentPositions|>Array.copy) 

而不是

yield currentPositions

在顺序和并行版本中一切正常。

为什么会发生这种情况;有没有最有效的方法来产生结果?预先感谢您;

最佳答案

问题是您正在创建一个单个数组,并且该数组在迭代之间发生变化。

您可以通过构建结果列表而不是逐一打印它们来消除等式中的并行性 - 如果您先构建列表,然后然后将它们全部打印出来,您将看到相同的结果;该列表将包含相同的引用 8 次,且始终指向同一数组实例。

基本上,为了避免副作用,您需要每个结果彼此独立 - 因此您应该每次创建一个单独的数组。

关于f# - F# 并行序列中的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7626978/

相关文章:

data-structures - 两个层次结构的单向同步

c# - 如何等到 await/async 方法完成

c# - 等待 ActionBlock<T> - TPL 数据流

f# - F# 是否支持模板或泛型?

wpf - 在 .fs 文件中引用 .xaml 文件中的事件

F# (mono) for VS Code on MacOS : bugs

.net - Task.WaitAll 的线程局部对象

c# - 一个任务可以有多个等待者吗?

c# - 如何使用任务有条件地异步运行代码

f# - 为什么在这种情况下 F# 不能推断类型?