Performance SEQ性能分解图
虽然将450 MB/6.6 Mio记录文件从磁盘上的Zip格式流式传输到内存中,作为一个序列工作时具有足够的性能,但通过Performance SEQ性能分解图,performance,dictionary,collections,f#,Performance,Dictionary,Collections,F#,虽然将450 MB/6.6 Mio记录文件从磁盘上的Zip格式流式传输到内存中,作为一个序列工作时具有足够的性能,但通过map.ofSeq将该序列转换为一个映射似乎实际上是不可能的: // within a let binding ... getPart fileName xPath partUri |> fun x -> printfn " getPart finished, parsing ..." ; x |> Seq.map (fun x -&g
map.ofSeq
将该序列转换为一个映射似乎实际上是不可能的:
// within a let binding ...
getPart fileName xPath partUri
|> fun x -> printfn " getPart finished, parsing ..." ; x |> Seq.map (fun x ->
let test name =
let x' = (xd x).Root.Descendants() |> Seq.filter (fun x'' -> x''
// do some System.Xml.Linq stuff here)
|> fun x -> printfn " Parsing finished, reorg seq ..." ; x |> Seq.map (fun x -> x.Reference, x )
|> fun x -> printfn " Reorg finished, building cell map... ### see this ### " ; x |> Map.ofSeq
do printfn "%s" " ### never see this ### done, now building keys..."
这是一个已知问题还是我犯了错误?正如@Petr在评论中提到的那样,
Seq
操作是惰性的,因此在任何工作完成之前,您的中间消息会立即打印出来
也就是说,如果您要创建一个非常大的查找表,那么Map.ofSeq
比其他选项要慢。下面是使用100万阵列进行的快速性能测试:
let rnd = System.Random()
let arr = Array.init 1000000 (fun i -> rnd.Next(), i) |> Seq.distinctBy fst |> Array.ofSeq
现在在我的机器上使用#time
,我得到以下数字:
#time
// 19 seconds
let m = Map.ofSeq arr
// 0.3 second
let d1 = dict arr
// 0.1 second
let d2 = System.Collections.Generic.Dictionary<int, int>(arr.Length)
for k, v in arr do d.Add(k, v)
#时间
//19秒
设m=等式arr的映射
//0.3秒
设d1=dict arr
//0.1秒
设d2=System.Collections.Generic.Dictionary(arr.Length)
对于阵列中的k,v,添加(k,v)
主要区别在于映射是不可变的,因此您可以添加和删除项目,同时保留映射的原始值。如果这是您需要的,那么map是最好的数据结构
相比之下,使用dict
创建一个只读字典(基于哈希表),可以快速查找,但创建后无法修改。最后,第三个选项创建一个普通的可变哈希表
Map.ofSeq
速度慢的部分原因还在于当前实现在每次插入后逐个添加元素并重新平衡树(数据的存储方式)。这可以用一种更聪明、更快的方式来完成(这对F#core libraries:-)是一个很好的贡献。我终于可以验证所观察到的性能崩溃是由XML转换引起的。所涉及的运行时间以小时为单位。重构XML转换后,我在数据集上观察到使用dict
大约2秒,使用Map
大约30秒。重构包括引入底层数据记录的固定内存布局。我怀疑这会对性能产生相关影响,但我没有单独衡量。Seq
是IEnumerable
-因此它是懒惰的Map.ofSeq
-不是懒惰的,所以它试图枚举序列的所有成员-因此性能受到影响在我的特定用例中,我处理转换为记录的XML片段。seq
的性能在~1分钟内测量。map
在超过20分钟后不会返回。我现在只使用seq
上的过滤来访问项目,在我的用例中,它的语法非常简洁。试试dict
函数,它应该会告诉你懒惰是否是原因问题,或者说是由于Map.ofSeq
速度慢造成的。