【问题标题】:Strange Behavior in F# Parallel SequenceF# 并行序列中的奇怪行为
【发布时间】:2011-10-02 22:45:41
【问题描述】:

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

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

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

为什么会这样;是否有最有效的方法来产生结果?提前谢谢你;

【问题讨论】:

    标签: f# task-parallel-library


    【解决方案1】:

    问题是您正在创建一个 single 数组,您在迭代之间进行变异。

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

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

    【讨论】:

    • 好的。我明白了,但为什么问题只出现在并行版本上?
    • @PanagiotisGrontas:它没有 - 正如我所说的,如果你将 allCombinations 的结果复制到一个列表并然后打印出该列表,你'会看到同样的事情。在第一种情况下,您只会看到“正确”的结果,因为您在每次迭代之间打印结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    • 1970-01-01
    相关资源
    最近更新 更多