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?
Mein erster Versuch war so:
%Vor% Aber aus irgendeinem Grund funktioniert es nicht - Variable a
wird None
.
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.
Das ist, was ich heraufkam:
Ссылка
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:
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:
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:
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 ...
Tags und Links python generator python-asyncio