2012-06-03 7 views
10

Considerate questo codice in F #:perché Seq.iter e Seq.map sono molto più lenti?

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!!!! 

Perché le iter e map funzioni del modulo Seq in modo molto più lento rispetto alle equivalenti Array e List modulo?

risposta

13

Dopo aver effettuato la chiamata a Seq, si perdono le informazioni sul tipo: lo spostamento verso l'elemento successivo nell'elenco richiede una chiamata allo IEnumerator.MoveNext. Confronta con per Array basta incrementare un indice e per List si può semplicemente dereferenziare un puntatore. In sostanza, ricevi una chiamata di funzione aggiuntiva per ciascun elemento nell'elenco.

Le conversioni di nuovo a List e Array anche rallentare il codice in basso per ragioni analoghe

+0

che abbia un senso, grazie per la segnalazione – theburningmonk

+0

Anche se lei ha probabilmente ragione circa la vera causa. In realtà non risponde alla domanda ad un livello più profondo. Perché hanno scelto di usare MoveNext. Come fatto attraverso la libreria linq si può iniziare con un controllo di tipo e nel caso di una lista o di un array scegliere la versione corrispondente quindi la differenza per le sequenze grandi sarebbe quindi trascurabile –