2012-06-03 58 views
10

考虑这个代码在F#:为什么Seq.iter和Seq.map如此之慢?

let n = 10000000 
let arr = Array.init n (fun _ -> 0) 

let rec buildList n acc i = if i = n then acc else buildList n (0::acc) (i + 1) 
let lst = buildList n [] 0 

let doNothing _ =() 
let incr x = x + 1 

#time 

arr |> Array.iter doNothing   // this takes 14ms 
arr |> Seq.iter doNothing   // this takes 74ms 

lst |> List.iter doNothing   // this takes 19ms 
lst |> Seq.iter doNothing   // this takes 88ms 

arr |> Array.map incr    // this takes 33ms 
arr |> Seq.map incr |> Seq.toArray // this takes 231ms! 

lst |> List.map incr    // this takes 753ms 
lst |> Seq.map incr |> Seq.toList // this takes 2111ms!!!! 

为什么Seq模块上的itermap功能比ArrayList模块等同这么多慢?

回答

13

一旦您拨打Seq,您将丢失类型信息 - 移至列表中的下一个元素需要致电IEnumerator.MoveNext。与Array相比,您只需增加一个索引,而对于List,则只需取消引用一个指针即可。实质上,您将获得列表中每个元素的额外函数调用。

的转换回ListArray也慢了下来代码出于类似的原因

+0

是有道理的,感谢您指出了这一点 – theburningmonk

+0

虽然你可能是正确的关于实际原因。它并没有真正在更深层次上回答这个问题。他们为什么选择使用MoveNext。如通过linq库完成的,您可以从类型检查开始,在列表或数组的情况下选择匹配版本,那么对于大型序列的差异将会忽略不计 –