2012-06-03 4 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!!!! 

Почему это iter и map функции на Seq модуле так гораздо медленнее, чем Array и List модулей эквивалентов?

ответ

13

После того, как вы позвоните в Seq, вы потеряете информацию о типе - для перехода к следующему элементу в списке требуется звонок IEnumerator.MoveNext. Сравните с Array вы просто увеличиваете индекс и для List вы можете просто разыменовать указатель. По сути, вы получаете дополнительный вызов функции для каждого элемента в списке.

Конверсии обратно List и Array также замедляет код вниз по аналогичным причинам

+0

, что имеет смысл, спасибо за указывая, что из – theburningmonk

+0

Хотя вы, вероятно, правы о фактической причине. Это не отвечает на вопрос на более глубоком уровне. Почему они решили использовать MoveNext. Как это сделано через библиотеку linq, вы можете начать с проверки типа, а в случае списка или массива выбрать подходящую версию, тогда разница для больших последовательностей будет тогда пренебрежимо малой –

 Смежные вопросы

  • Нет связанных вопросов^_^