2009-04-03 5 views
120

Was ist der Unterschied zwischen einer Coroutine und eine Fortsetzung und ein Generator?Coroutine vs Fortsetzung vs Generator

+1

Ich frage mich, ob Korotinen und Fortsetzungen effektiv gleichwertig sind. Ich weiß, dass es möglich ist, Koroutinen mit Fortsetzungen zu modellieren, aber ist es möglich, Fortsetzungen mit Korotinen zu modellieren oder nicht, weil Fortsetzungen strikter sind? – nalply

Antwort

102

Ich fange mit Generatoren an, da sie der einfachste Fall sind. Als @zvolkov erwähnt, sind sie Funktionen/Objekte, die wiederholt aufgerufen werden können, ohne zurück zu geben, aber wenn sie aufgerufen werden, werden sie einen Wert zurückgeben (yield) und dann ihre Ausführung unterbrechen. Wenn sie wieder angerufen werden, werden sie von dort aus starten, wo sie zuletzt die Ausführung ausgesetzt haben und ihr Ding wieder tun.

Ein Generator ist im wesentlichen eine Senkung (asymmetrisch) Koroutine. Der Unterschied zwischen einer Coroutine und einem Generator besteht darin, dass eine Coroutine Argumente akzeptieren kann, nachdem sie anfänglich aufgerufen wurde, während ein Generator dies nicht kann.

Es ist ein bisschen schwierig, einige sich mit einem trivialen Beispiel, wo Sie Koroutinen verwenden würde, aber hier ist mein Bestes versuchen. Nehmen Sie diesen (erfundenen) Python-Code als Beispiel.

def my_coroutine_body(*args): 
    while True: 
     # Do some funky stuff 
     *args = yield value_im_returning 
     # Do some more funky stuff 

my_coro = make_coroutine(my_coroutine_body) 

x = 0 
while True: 
    # The coroutine does some funky stuff to x, and returns a new value. 
    x = my_coro(x) 
    print x 

Ein Beispiel, wo Koroutinen verwendet werden, ist lexers und Parser. Ohne Korotinen in der Sprache oder irgendwie emuliert, muss Lexing und Parsing-Code zusammengemischt werden, obwohl sie wirklich zwei getrennte Anliegen sind. Mit einer Coroutine können Sie jedoch den Lexing- und Parsing-Code trennen.

(Ich werde den Unterschied zwischen symmetrischen und asymmetrischen Coroutines putzen. Es genügt zu sagen, dass sie gleichwertig sind, können Sie von einem zum anderen konvertieren, und asymmetrische Koroutinen - die am meisten wie Generatoren sind - Das ist leichter zu verstehen. Ich skizzierte, wie man asymmetrische Coroutinen in Python implementieren könnte.

Continuations sind eigentlich ganz einfache Bestien. Sie sind alle Funktionen, die einen anderen Punkt im Programm darstellen. Wenn Sie es aufrufen, wird die Ausführung automatisch zu dem Punkt wechseln, den die Funktion darstellt. Sie verwenden jeden Tag sehr eingeschränkte Versionen von ihnen, ohne es zu merken. Ausnahmen können zum Beispiel als eine Art von Inside-Out-Fortsetzung betrachtet werden. Ich gebe Ihnen ein Python-basiertes Pseudocode-Beispiel einer Fortsetzung.

Sagen Python hatte eine Funktion mit dem Namen callcc(), und diese Funktion nahm zwei Argumente, von denen das erste eine Funktion ist, und das zweite eine Liste von Argumenten, um es aufzurufen. Die einzige Einschränkung für diese Funktion wäre, dass das letzte Argument eine Funktion ist (was unsere aktuelle Fortsetzung sein wird).

def foo(x, y, cc): 
    cc(max(x, y)) 

biggest = callcc(foo, [23, 42]) 
print biggest 

Was passieren würde, ist, dass callcc() würde wiederum Anruf foo() mit der aktuellen Fortsetzung (cc), das heißt, ein Verweis auf die Stelle im Programm, an dem callcc() genannt wurde. Wenn foo() die aktuelle Fortsetzung aufruft, ist es im Wesentlichen dasselbe wie callcc() mit dem Wert zurückzugeben, den Sie die aktuelle Fortsetzung aufrufen, und wenn dies der Fall ist, wird der Stapel an die Stelle zurückgesetzt, an der die aktuelle Fortsetzung erstellt wurde, dh wann Sie haben callcc() angerufen.

Das Ergebnis von all dem wäre, dass unsere hypothetische Python-Variante '42' drucken würde.

Ich hoffe, dass hilft, und ich bin sicher, dass meine Erklärung einiges verbessert werden kann!

+6

One nit: _delimited_ Fortsetzungen sind Funktionen, aber _undelimited_ Fortsetzungen sind nicht: http://okmij.org/ftp/continuations/undelimited.html#delim-vs-undelim –

+2

Das ist ein guter Punkt. Das heißt, in den meisten praktischen Anwendungen, wenn Leute "Fortführung" sagen, sprechen sie von partiellen/abgegrenzten Fortsetzungen. Das Einbringen der verschiedenen anderen Arten von Fortsetzungen hätte die Erklärung etwas durcheinander gebracht. –

+1

Fortsetzungen sind keine Funktionen, obwohl sie in Funktionen verdinglicht werden können. "In den meisten praktischen Anwendungen, wenn die Leute" Fortführung "sagen, sprechen sie von partiellen/begrenzten Fortsetzungen." Würden Sie auf eine solche Verwendung des Begriffs "Fortsetzung" hinweisen? Ich habe noch nie solche Verwendung getroffen. Außerdem haben Sie ein Beispiel für eine unbegrenzte Fortsetzung gegeben, indem Sie call/cc verwenden. Die Operatoren für begrenzte Fortsetzungen werden normalerweise "zurückgesetzt" und "verschoben" (sie können andere Namen haben). – Ivancho

28

Coroutine ist eines von mehreren Verfahren, die abwechselnd ihre Arbeit tun nehmen und dann Pause Steuerung zu den anderen Koroutinen in der Gruppe zu geben.

Fortsetzung ist ein „Zeiger auf eine Funktion“ Sie zu einem gewissen Prozedur übergeben, ausgeführt werden („fortgesetzt mit“), wenn das Verfahren durchgeführt wird.

Generator (in NET) ist ein Sprachkonstrukt, das einen Wert auszuspucken kann, „Pause“ Ausführung des Verfahrens und dann vom selben Punkt gehen, wenn für den nächsten Wert gefragt.

+0

Ich weiß, dass die Antwort vielleicht nicht genau ist, aber auf dieser Ebene der Frage habe ich versucht, es einfach zu halten. Außerdem verstehe ich das alles selbst nicht richtig :) – zvolkov

+0

Ein Generator in Python ist ähnlich wie die C# -Version, ist aber als spezielle Syntax zum Erstellen einer Instanz eines Iterator-Objekts implementiert, das die von der Funktion zurückgegebenen Werte zurückgibt "Definition, die Sie bereitstellen. – Benson

+2

Eine kleine Korrektur: "... einschließlich Call-Stack und alle Variablen, aber nicht ihre Werte" (oder einfach "alle Variablen"). Fortsetzungen behalten die Werte nicht bei, sie enthalten nur den Aufrufstapel. – nalply

7

In der neueren Version von Python können Sie Werte an Generatoren mit generator.send() senden, die Python-Generatoren effektiv Koroutinen macht.

Der Hauptunterschied zwischen Python Generator und anderen Generator, sagen Greenlet, ist, dass in Python Ihre yield value nur zurück zum Aufrufer zurückgeben kann. Während in Greenlet, kann target.switch(value) Sie zu einer bestimmten Ziel-Coroutine führen und einen Wert ergeben, bei dem die target weiter ausgeführt werden würde.

+3

Aber in Python müssen alle 'Yield'-Aufrufe in derselben Funktion sein, die "Generator" genannt wird. Sie können von einer Unterfunktion nicht "nachgeben", weshalb Pythons * Semi-Coroutinen * genannt werden, während Lua * asymmetrische Coroutinen * hat. (Es gibt Vorschläge, die Erträge zu propagieren, aber ich denke, dass diese nur die Gewässer trüben.) – cdunn2001

+4

@ cdunn2001: (Kommentar von Winston) Python3.3 führte den Ausdruck "yield from" ein, mit dem Sie vom Untergenerator profitieren können. –

Verwandte Themen