Was ist der beste Weg, um Generatoren-Pipeline als Koroutinen umzuformen?

9

Betrachten Sie diesen Code:

%Vor%

Dies ist die Illustration einer Pipeline aus Generatoren. Ich benutze dieses Muster häufig in der Praxis, um einen Datenverarbeitungsfluss aufzubauen. Es ist wie UNIX-Pipes.

Was ist der eleganteste Weg, um die Generatoren zu Korotinen umzuformen, die die Ausführung jedes yield aussetzen?

AKTUALISIEREN

Mein erster Versuch war so:

%Vor%

Aber aus irgendeinem Grund funktioniert es nicht - Variable a wird None .

UPDATE # 1

Was ich vor kurzem herausgefunden habe:

Server:

%Vor%

Kunde:

%Vor%

Vorteil gegenüber "David Beazleys Koroutinen" ist, dass Sie alle asyncio sachen in solchen Verarbeitungseinheiten mit% co_de verwenden können % und input Warteschlangen.
Nachteil hier - eine Menge Warteschlangeninstanzen, die zum Verbinden von Pipeline-Einheiten benötigt werden. Es kann mit der Verwendung von Datenstruktur höher als output behoben werden.
Ein weiterer Nachteil besteht darin, dass diese Art von Verarbeitungseinheiten ihre Ausnahmen nicht an einen übergeordneten Stapelrahmen weitergibt, da sie "Hintergrundaufgaben" sind, während "David Beazleys Koroutinen" propagiert.

UPDATE # 2

Das ist, was ich heraufkam:
Ссылка

    
Gill Bates 30.11.2014, 08:35
quelle

1 Antwort

4

Ich denke, die Antwort hier ist "du nicht". Ich vermute, dass Sie diese Idee von David Beazleys berühmtem Coroutine / Generator-Tutorial bekommen. In seinen Tutorials verwendet er Coroutinen als eine im Prinzip umgekehrte Generator-Pipeline. Anstatt die Daten durch Iterieren über Generatoren durch die Pipeline zu ziehen, pushen Sie Daten mit gen_object.send() durch die Pipeline. Ihr erstes Beispiel würde so aussehen, wenn Sie diesen Begriff von Koroutinen verwenden:

%Vor%

Nun sind die Koroutinen in asyncio ähnlich, da sie suspendierbare Generatorobjekte sind, an die Daten gesendet werden können, aber sie sind wirklich nicht für den Anwendungsfall der Datenpipelines gedacht. Sie sollen verwendet werden, um Parallelität zu ermöglichen, wenn Sie blockierende E / A-Vorgänge ausführen. Die yield from -Unterbrechungspunkte ermöglichen es der Steuerung, zu der Ereignisschleife zurückzukehren, während die E / A auftritt, und die Ereignisschleife startet die Coroutine neu, wenn sie abgeschlossen ist, und sendet die durch den E / A-Aufruf zurückgegebenen Daten in die Coroutine. Es gibt wirklich keinen praktischen Grund, sie für diese Art von Anwendungsfall zu verwenden, da es überhaupt keine blockierenden E / A-Vorgänge gibt.

Das Problem mit asyncio besteht auch darin, dass a = yield from coro() dem Rückgabewert von coro einen Wert zuweist. Aber du gibst nichts von coro zurück. Sie sind irgendwo zwischen der Behandlung von coro als eine tatsächliche Coroutine und einem Generator gefangen. Es sieht so aus, als ob Sie yield from future erwarten, um den Inhalt von future von coro an coro2 zu senden, aber so funktionieren Koroutinen nicht. yield from wird verwendet, um Daten aus einer Coroutine / Future / Task zu holen, und return wird verwendet, um ein Objekt tatsächlich an den Aufrufer zu senden. Also, für coro , um tatsächlich etwas zu coro2 zurückzugeben, müssen Sie dies tun:

%Vor%

Aber das wird nur damit enden, dass 'a' an coro2 zurückgegeben wird. Ich denke, um die Ausgabe zu erhalten, die Sie erwarten, müssen Sie dies tun:

%Vor%

Was vielleicht zeigt, warum asyncio coroutines nicht das ist, was Sie hier wollen.

Bearbeiten:

Ok, in einem Fall, in dem Sie zusätzlich zur eigentlichen Verwendung von asynchronen E / A-Pipelines Pipelining verwenden möchten, ist der Ansatz, den Sie in Ihrem Update verwendet haben, gut. Wie Sie vorgeschlagen haben, kann dies vereinfacht werden, indem Sie eine Datenstruktur erstellen, um die Warteschlangenverwaltung zu automatisieren:

%Vor%

Dies vereinfacht Queue management, behebt aber nicht das Problem der Ausnahmebehandlung. Ich bin mir nicht sicher, ob da viel getan werden kann ...

    
dano 01.12.2014 17:03
quelle