2012-06-03 60 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庫完成的,您可以從類型檢查開始,在列表或數組的情況下選擇匹配版本,那麼對於大型序列的差異將會忽略不計 –