Panagiotis Grontas
Panagiotis Grontas

Reputation: 143

Strange Behavior in F# Parallel Sequence

I have written the following code to generate all possible combinations of some numbers:

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            
   } 

I am consuming the sequence in some other part of the program like this:

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

So far so good. The programs runs as expected and generates the combinations. For input [|2;2;2|] it generates the eight values:

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

However when I use PSeq to parallelise the generated sequence all values to be consumed change to [|2;0;0|] which is the last value of the currentPositions array in the while loop above.

If i use

yield (currentPositions|>Array.copy) 

instead of

yield currentPositions

everything works ok in both sequential and parallel versions.

Why does this happen; Is there a most efficient way to yield the result; Thank you in advance;

Upvotes: 2

Views: 215

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1502036

The problem is that you're creating a single array which you're mutating between iterations.

You can take the parallelism out of the equation by building a list of the results instead of printing them out one by one - if you build the list first and then print them all, you'll see the same result; the list will contain the same reference 8 times, always to the same array instance.

Basically to avoid side-effects, you need each result to be independent of the other - so you should create a separate array each time.

Upvotes: 3

Related Questions