2011-10-02 179 views
2

我寫了下面的代碼來生成一些數字的所有可能的組合:奇怪的行爲

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到parallelise所生成的序列的所有值被消耗變化到[| 2; 0; 0 |]這是上面while循環中currentPositions數組的最後一個值。

如果我使用

yield (currentPositions|>Array.copy) 

,而不是

yield currentPositions 

一切工作的串行和並行兩種版本確定。

爲什麼會發生這種情況;有沒有一種最有效的方法來產生結果;先謝謝你;

回答

3

問題是,你正在創建一個單個的數組,你在迭代之間進行變異。

您可以通過構建結果的列表,而不是由一個印刷出來一個以並行的方程 - 如果第一和建立列表,然後全部打印出來,你會看到同樣的結果;該列表將包含8次相同的引用,始終是相同的數組實例。

基本上要避免副作用,你需要每個結果獨立於另一個 - 所以你應該每次創建一個單獨的數組。

+0

好的。我明白了,但爲什麼問題只出現在並行版本上? –

+3

@PanagiotisGrontas:它沒有 - 正如我所說的,如果您將allCombinations的結果複製到列表中,然後將列表打印出來,您將看到同樣的結果。在第一種情況下,您只會看到「正確」的結果,因爲您要在每次迭代之間打印結果*。 –