为什么Frame.ofRecords在输入由并行计算生成的序列时会使其结果变得复杂?

时间:2017-08-28 21:08:38

标签: parallel-processing f# deedle

我正在运行一些计算记录序列的代码,并以该序列作为参数调用Frame.ofRecords。记录使用库PSeq.map中的FSharp.Collections.ParallelSeq计算。

如果我将序列转换为列表,则输出正常。这是代码和输出:

let summaryReport path (writeOpenPolicy: WriteOpenPolicy) (outputs: Output seq) =
    let foo (output: Output) =
        let temp =
            { Name          = output.Name
              Strategy      = string output.Strategy
              SharpeRatio   = (fst output.PandLStats).SharpeRatio
              CalmarRatio   = (fst output.PandLStats).CalmarRatio }
        printfn "************************************* %A" temp
        temp
    outputs
    |> Seq.map foo
    |> List.ofSeq // this is the line that makes a difference
    |> Frame.ofRecords
    |> frameToCsv path writeOpenPolicy ["Name"] "Summary_Statistics"


Name    Name        Strategy    SharpeRatio CalmarRatio
0   Singleton_AAPL  MyStrategy  0.317372564 0.103940018
1   Singleton_MSFT  MyStrategy  0.372516931 0.130150478
2   Singleton_IBM   MyStrategy              Infinity

printfn命令让我通过检查验证在每种情况下都正确计算了变量temp。 最后一个代码行只是FrameExtensions.SaveCsv的包装。

如果我删除|> List.ofSeq行,那么出现的内容就是乱码:

Name    Name        Strategy    SharpeRatio CalmarRatio
0   Singleton_IBM   MyStrategy  0.317372564 0.130150478
1   Singleton_MSFT  MyStrategy              0.103940018
2   Singleton_AAPL  MyStrategy  0.372516931 Infinity

请注意,空(对应于NaN)和Infinity项目现在位于不同的行中,其他内容也会混淆。

为什么会这样?

2 个答案:

答案 0 :(得分:4)

Frame.ofRecords函数多次遍历序列,因此如果您的序列在重复调用时返回不同的数据,则会在帧中获得不一致的数据。

这是一个最小的例子:

let mutable n = 0.
let nums = seq { for i in 0 .. 10 do n <- n + 1.; yield n, n }

Frame.ofRecords nums

返回:

      Item1 Item2 
0  -> 1     12    
1  -> 2     13    
2  -> 3     14    
3  -> 4     15    
4  -> 5     16    
5  -> 6     17    
6  -> 7     18    
7  -> 8     19    
8  -> 9     20    
9  -> 10    21    
10 -> 11    22    

如您所见,第一个项目是在序列的第一次迭代中获得的,而第二个项目是在第二次迭代中获得的。

这可能应该更好地记录,但它会使典型情况下的性能更好 - 如果您可以向文档发送PR,那将是有用的。

答案 1 :(得分:1)

并行序列以任意顺序运行,因为它们在许多处理器中被分割,因此结果集将是随机顺序。您可以随后对它们进行排序,也可以不并行运行数据。