Dies ist eine Optimierung, die vom F # -Compiler durchgeführt wird. Soweit ich weiß, wurde es später tatsächlich implementiert - der F # Compiler hatte zuerst eine Listenkomprehension, dann eine allgemeine Version von Berechnungsausdrücken (auch für seq { ... }
verwendet), aber das war weniger effizient, daher wurde die Optimierung in einer späteren Version hinzugefügt .
Der Hauptgrund ist, dass dadurch viele Zuweisungen und Umleitungen entfernt werden. Angenommen, Sie haben so etwas wie:
seq { for i in input do
yield i
yield i * 10 }
Wenn Ausdrücke Berechnung verwendet wird, wird dies wie etwas übersetzt:
seq.Delay(fun() -> seq.For(input, fun i ->
seq.Combine(seq.Yield(i), seq.Delay(fun() -> seq.Yield(i * 10)))))
Es gibt ein paar Funktionszuordnungen und die For
Schleife immer die Lambda muss aufrufen Funktion. Die Optimierung verwandelt dies in eine Zustandsmaschine (ähnlich der C# -Zustandsmaschine), so dass die Operation MoveNext()
auf dem generierten Enumerator einfach einen Zustand der Klasse mutiert und dann zurückgibt ...
Sie können die Leistung leicht vergleichen, indem Sie definieren eine individuelle Berechnung Builder für Sequenzen:
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 |]
Jetzt können wir dies testen (#time
in F # interaktiv verwenden):
for i in 0 .. 10000 do
mseq { for x in input do
yield x
yield x * 10 }
|> Seq.length |> ignore
auf meinem Computer, nimmt diese 2.644sec, wenn die benutzerdefinierte 012 mitBuilder aber nur 0,065 Sekunden bei Verwendung der integrierten optimierten seq
Ausdruck. Die Optimierung macht Sequenz-Ausdrücke somit deutlich effizienter.
Vielleicht ist es erwähnenswert, dass Sie Ihre benutzerdefinierten Builder-Methoden "Inline", um einige Optimierungen zu erhalten. – t0yv0
@TomasPetricek: Gibt es eine Möglichkeit, MSeqBuilder neu zu schreiben, so dass Code erzeugt wird, der näher an der optimierten State Machine Version liegt? – user1411900
@toyvo Das ist ein toller Punkt. Das sollte es schneller machen. –