Questa è un'ottimizzazione eseguita dal compilatore F #. Per quanto ne so, è stato implementato in un secondo momento: il compilatore F # aveva prima le list comprehensions, quindi una versione general-purpose delle espressioni di calcolo (usata anche per seq { ... }
) ma meno efficiente, quindi l'ottimizzazione è stata aggiunta in qualche versione successiva .
Il motivo principale è che questo rimuove molte allocazioni e riferimenti indiretti. Diciamo che hai qualcosa di simile:
seq { for i in input do
yield i
yield i * 10 }
Quando si utilizzano le espressioni di calcolo, questo si traduce in qualcosa di simile:
seq.Delay(fun() -> seq.For(input, fun i ->
seq.Combine(seq.Yield(i), seq.Delay(fun() -> seq.Yield(i * 10)))))
C'è un paio di allocazioni di funzione e il ciclo For
ha sempre bisogno di invocare il lambda funzione. L'ottimizzazione lo trasforma in una macchina a stati (simile alla macchina a stati C#), quindi l'operazione MoveNext()
sull'enumeratore generato modifica semplicemente alcuni stati della classe e quindi restituisce ...
È possibile confrontare facilmente le prestazioni definendo un costruttore personalizzato di calcolo per le sequenze:
type MSeqBuilder() =
member x.For(en, f) = Seq.collect f en
member x.Yield(v) = Seq.singleton v
member x.Delay(f) = Seq.delay f
member x.Combine(a, b) = Seq.concat [a; b]
let mseq = MSeqBuilder()
let input = [| 1 .. 100 |]
Ora possiamo testare questo (utilizzando #time
in F # interattivo):
for i in 0 .. 10000 do
mseq { for x in input do
yield x
yield x * 10 }
|> Seq.length |> ignore
Sul mio computer, questo prende 2.644sec quando si utilizza l'usanza 012 Generatorema solo 0,065 secondi se si utilizza l'espressione integrata seq
ottimizzata. Quindi l'ottimizzazione rende le espressioni di sequenza significativamente più efficienti.
Vale la pena notare che è possibile "incorporare" i metodi del builder personalizzato per ottenere un'ottimizzazione. – t0yv0
@TomasPetricek: Esiste un modo per riscrivere MSeqBuilder in modo che generi codice più vicino alla versione ottimizzata della macchina di stato? – user1411900
@toyvo Questo è un grande punto. Questo dovrebbe renderlo più veloce. –