为什么 Frame.ofRecords 在输入由并行计算生成的序列时会出现乱码?
Why does Frame.ofRecords garbles its results when fed a sequence generated by a parallel calculation?
我是 运行 一些计算记录序列并以该序列作为参数调用 Frame.ofRecords
的代码。记录是使用库 FSharp.Collections.ParallelSeq
.
中的 PSeq.map
计算得出的
如果我将序列转换为列表,那么输出就可以了。这是代码和输出:
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
项现在在不同的行中,其他的东西也混在一起了。
为什么会这样?
并行序列 运行 是任意顺序的,因为它们被拆分到许多处理器上,因此结果集将是随机顺序的。您可以随时对它们进行排序,或者不运行并行处理您的数据。
Frame.ofRecords
函数多次遍历序列,所以如果你的序列returns重复调用不同的数据,你会得到不一致的数据到帧中。
这是一个最小的例子:
let mutable n = 0.
let nums = seq { for i in 0 .. 10 do n <- n + 1.; yield n, n }
Frame.ofRecords nums
这个returns:
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,那将很有用。
我是 运行 一些计算记录序列并以该序列作为参数调用 Frame.ofRecords
的代码。记录是使用库 FSharp.Collections.ParallelSeq
.
PSeq.map
计算得出的
如果我将序列转换为列表,那么输出就可以了。这是代码和输出:
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
项现在在不同的行中,其他的东西也混在一起了。
为什么会这样?
并行序列 运行 是任意顺序的,因为它们被拆分到许多处理器上,因此结果集将是随机顺序的。您可以随时对它们进行排序,或者不运行并行处理您的数据。
Frame.ofRecords
函数多次遍历序列,所以如果你的序列returns重复调用不同的数据,你会得到不一致的数据到帧中。
这是一个最小的例子:
let mutable n = 0.
let nums = seq { for i in 0 .. 10 do n <- n + 1.; yield n, n }
Frame.ofRecords nums
这个returns:
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,那将很有用。