Yield Keyword Value Added?

8

versuche immer noch zu finden, wo ich das "yield" -Schlüsselwort in einer realen Situation verwenden würde.

Ich sehe diesen Thread zum Thema

Wie lautet das Keyword "yield" in C #?

aber in der akzeptierten Antwort haben sie dies als ein Beispiel, wo jemand um Integers ()

iteriert %Vor%

aber warum nicht einfach

verwenden %Vor%

hier stattdessen. scheint einfacher ..

    
leora 21.12.2008, 12:24
quelle

10 Antworten

23

Wenn Sie eine Liste erstellen und zurückgeben (sagen wir, sie hat 1 Million Elemente), ist das ein großer Teil des Speichers und auch der Arbeit, um sie zu erstellen.

Manchmal möchte der Anrufer vielleicht nur wissen, was das erste Element ist. Oder sie möchten sie in eine Datei schreiben, wenn sie sie erhalten, anstatt die gesamte Liste im Speicher zu erstellen und sie dann in eine Datei zu schreiben.

Aus diesem Grund ist es sinnvoller, Rendite zu verwenden. Es sieht nicht so anders aus, als die gesamte Liste zu erstellen und zurückzugeben, aber es ist sehr unterschiedlich, weil die gesamte Liste nicht im Speicher erstellt werden muss, bevor der Aufrufer das erste Element darauf betrachten kann.

Wenn der Anrufer sagt:

%Vor%

Jedes Mal, wenn die Schleife ein neues i erfordert, führt sie etwas mehr Code in Integers () aus. Der Code in dieser Funktion ist "pausiert", wenn er eine yield return -Anweisung trifft.

    
Daniel Earwicker 21.12.2008, 12:34
quelle
9
Mit

Yield können Sie Methoden erstellen, mit denen Daten erzeugt werden, ohne dass vor dem Zurückkehren alles gesammelt werden muss. Betrachten Sie es als Rückgabe mehrerer Werte auf dem Weg.

Hier sind ein paar Methoden, die den Punkt verdeutlichen:

%Vor%

Keine dieser beiden Methoden liest den gesamten Inhalt der Datei in den Speicher, aber Sie können sie wie folgt verwenden:

%Vor%     
quelle
4

Sie können yield verwenden, um einen Iterator zu erstellen. Das könnte eine träge ausgewertete Serie sein (z. B. Zeilen aus einer Datei oder Datenbank lesen, ohne alles auf einmal zu lesen, was zu viel im Speicher sein könnte), oder könnte über bestehende Daten wie zB List<T> iterieren.

C # in der Tiefe hat ein freies Kapitel (6) alles über Iteratorblöcke.

Ich habe auch kürzlich gebloggt über die Verwendung von yield für Smart Brute -force-Algorithmen.

Ein Beispiel für den faulen Dateireader:

%Vor%

Das ist völlig "faul"; nothing wird gelesen, bis Sie mit dem Aufzählen beginnen und nur eine einzige Zeile im Speicher gehalten wird.

Beachten Sie, dass LINQ-to-Objects extensive Verwendung von Iterator-Blöcken ( yield ) macht. Zum Beispiel ist die Erweiterung Where im Wesentlichen:

%Vor%

Und wieder ganz faul - Sie können mehrere Operationen aneinanderreihen, ohne dass alles in den Speicher geladen werden muss.

    
Marc Gravell 21.12.2008 12:35
quelle
3
Mit

yield können Sie Sammlungen verarbeiten, deren Größe potentiell unendlich ist, da die gesamte Sammlung niemals auf einmal im Speicher geladen wird, im Gegensatz zu einem auf Listen basierenden Ansatz. Zum Beispiel ein IEnumerable & lt; & gt; von allen Primzahlen könnte durch die entsprechende Algo für die Suche nach den Primzahlen, während eine Liste Ansatz immer in der Größe und damit unvollständig sein würde. In diesem Beispiel ermöglicht die Verwendung von yield auch die Verarbeitung des nächsten Elements, das zurückgestellt werden soll, bis es benötigt wird.

    
spender 21.12.2008 12:38
quelle
1

Eine echte Situation für mich ist, wenn ich eine Sammlung verarbeiten möchte, die eine Weile dauert, um sie besser zu bevölkern.

Stellen Sie sich etwas vor (pseudo-Code):

%Vor%

Anstatt eine Minute warten zu müssen, bis die Sammlung gefüllt ist, kann ich mit der Verarbeitung von Elementen beginnen. Ich kann sofort starten und dann auf der Benutzerschnittstelle melden, wie es passiert.

    
user48112 21.12.2008 12:43
quelle
1

Sie möchten vielleicht nicht immer yield verwenden, anstatt eine Liste zurückzugeben, und in Ihrem Beispiel verwenden Sie yield, um tatsächlich eine Liste von ganzen Zahlen zurückzugeben. Je nachdem, ob Sie eine veränderbare Liste oder eine unveränderliche Sequenz wünschen, können Sie eine Liste oder einen Iterator (oder eine andere Sammlung mutable / immutable) verwenden.

Aber es gibt Vorteile, den Ertrag zu verwenden.

  • Yield bietet eine einfache Möglichkeit, faul bewertete Iteratoren zu erstellen. (Das bedeutet, dass nur der Code zum Abrufen des nächsten Elements in Folge ausgeführt wird, wenn die MoveNext () -Methode aufgerufen wird, dann gibt der Iterator keine Berechnungen mehr zurück, bis die Methode erneut aufgerufen wird)

  • Yield baut eine Zustandsmaschine unter den Deckeln auf, und das erspart Ihnen viel Arbeit, da Sie nicht die Zustände Ihres generischen Generators codieren müssen = & gt; prägnanter / einfacher Code.

  • Yield erstellt automatisch optimierte und threadsichere Iteratoren und erspart Ihnen die Details zur Erstellung.

  • Ausbeute ist viel mächtiger als es auf den ersten Blick scheint und kann für viel mehr als nur einfache Iteratoren verwendet werden. In diesem Video finden Sie Pop Catalin 21.12.2008 13:15

quelle
0

Vielleicht möchten Sie verschiedene Sammlungen durchlaufen:

%Vor%     
Trap 21.12.2008 12:33
quelle
0

Ich stimme allem zu, was alle hier über faule Evaluierung und Speichernutzung gesagt haben, und wollte ein weiteres Szenario hinzufügen, in dem ich festgestellt habe, dass die Iteratoren das Schlüsselwort yield nützlich finden. Ich bin auf einige Fälle gestoßen, in denen ich eine Sequenz von möglicherweise kostspieliger Verarbeitung einiger Daten ausführen muss, bei denen es äußerst nützlich ist, Iteratoren zu verwenden. Anstatt die gesamte Datei sofort zu verarbeiten oder eine eigene Verarbeitungspipeline zu erstellen, kann ich Iteratoren einfach so verwenden:

%Vor%

Der Vorteil hier ist, dass, indem ich die Ein- und Ausgabe auf alle Funktionen IEnumerable<double> belasse, meine Verarbeitungspipeline vollständig zusammensetzbar, leicht zu lesen und faul ist, so dass ich nur die Verarbeitung machen muss, die ich wirklich machen muss . Dadurch kann ich fast alle meine Verarbeitungen in den GUI-Thread einfügen, ohne die Reaktionsfähigkeit zu beeinflussen, so dass ich mich nicht um Threading-Probleme kümmern muss.

    
Jon Norton 21.12.2008 13:04
quelle
0

Ich kam auf, um zu überwinden, .net Manko, die List manuell manuell zu kopieren.

Ich benutze das:

%Vor%

Und an einem anderen Ort:

%Vor%

Ich habe versucht, oneliner zu finden, der das tut, aber es ist nicht möglich, weil es nicht funktioniert, wenn es in anonymen Methodenblöcken funktioniert.

BEARBEITEN:

Besser noch, benutze generische List cloner:

%Vor%     
Daniel Mošmondor 30.09.2009 09:50
quelle
0

Die Methode, die von yield verwendet wird, um Arbeitsspeicher zu sparen, indem man Objekte on-the-fly verarbeitet, ist nett, aber es ist wirklich nur syntaktischer Zucker. Es ist schon lange her. In jeder Sprache, die Funktions- oder Schnittstellenzeiger (auch C und Assembly) hat, können Sie den gleichen Effekt mit einer Callback-Funktion / Schnittstelle erzielen.

Dieses ausgefallene Zeug:

%Vor%

ist im Grunde äquivalent zu altmodisch:

%Vor%     
Matthew 17.02.2010 07:14
quelle

Tags und Links