Asynchrone und CPU-gebundene Python-Aufgaben?

Ich habe vor kurzem an einem Haustierprojekt in Python mit Kolben gearbeitet. Es ist ein einfaches Pastebin mit serverseitiger Syntax, die die Unterstützung von Pygments hervorhebt. Da dies eine kostspielige Aufgabe ist, habe ich die Syntaxhervorhebung an eine Sellerie-Aufgabenwarteschlange delegiert und im Anforderungshandler darauf gewartet, dass sie abgeschlossen ist. Es ist unnötig zu erwähnen, dass dies nicht mehr als die CPU-Auslastung eines anderen Arbeiters verringert, da das Warten auf ein Ergebnis die Verbindung zum Webserver weiterhin sperrt. Obwohl mein Instinkt mich aufforderte, vorzeitige Optimierungen wie die Pest zu vermeiden, konnte ich mir immer noch nicht helfen, mich mit Async auseinanderzusetzen.

Async

Wenn Sie in letzter Zeit die Python-Webentwicklung verfolgt haben, haben Sie sicherlich gesehen, dass Async überall ist. Async bringt kooperatives Multitasking zurück, was bedeutet, dass jeder "Thread" entscheidet, wann und wo er einem anderen nachgibt. Dieser nicht vorbeugende Prozess ist effizienter als Betriebssystem-Threads, weist jedoch immer noch Nachteile auf. Im Moment scheint es zwei Hauptansätze zu geben:

Multitasking im Event- / Callback-StilCoroutinen

Der erste bietet Parallelität durch lose gekoppelte Komponenten, die in einer Ereignisschleife ausgeführt werden. Obwohl dies in Bezug auf die Rennbedingungen sicherer und konsistenter ist, ist es wesentlich weniger intuitiv und schwieriger zu codieren als präventives Multitasking.

Die andere ist eine traditionellere Lösung, die dem Thread-Programmierstil näher kommt, da der Programmierer den Kontext nur manuell wechseln muss. Obwohl es anfälliger für Rennbedingungen und Deadlocks ist, bietet es eine einfache Drop-In-Lösung.

Die meiste asynchrone Arbeit wird im Moment auf dem sogenannten erledigtIO-gebunden Aufgaben, Aufgaben, die das Warten auf Eingabe oder Ausgabe blockieren. Dies wird normalerweise durch die Verwendung von Polling- und Timeout-basierten Funktionen erreicht, die aufgerufen werden können. Wenn sie negativ zurückkehren, kann der Kontext gewechselt werden.

Trotz des Namens könnte dies angewendet werdenCPU-gebunden Auch Aufgaben, die an einen anderen Mitarbeiter (Thread, Prozess usw.) delegiert werden können und dann ohne zu blockieren darauf gewartet werden, dass sie ausgeführt werden. Idealerweise würden diese Tasks asynchron geschrieben, aber realistisch gesehen würde dies bedeuten, dass der Code in so kleine Blöcke aufgeteilt wird, dass er nicht blockiert wird, vorzugsweise ohne Streuung der Kontextwechsel nach jeder Codezeile. Dies ist insbesondere für vorhandene synchrone Bibliotheken unpraktisch.

Aus Bequemlichkeitsgründen habe ich mich für die asynchrone Arbeit mit gevent entschieden und mich gefragt, wie mit CPU-gebundenen Aufgaben in einer asynchronen Umgebung umgegangen werden soll (mit Futures, Sellerie usw.?).

Wie verwende ich asynchrone Ausführungsmodelle (in diesem Fall gevent) mit herkömmlichen Web-Frameworks wie flask? Was sind einige gemeinsam vereinbarte Lösungen für diese Probleme in Python (Futures, Task Queues)?

BEARBEITEN: Um genauer zu sein - Wie verwende ich gevent mit flask und wie gehe ich in diesem Zusammenhang mit CPU-gebundenen Aufgaben um?

EDIT2: In Anbetracht dessen, wie Python die GIL hat, die eine optimale Ausführung von Thread-Code verhindert, bleibt zumindest in meinem Fall nur die Multiprocessing-Option. Dies bedeutet entweder mitconcurrent.futures oder ein anderer externer Dienst, der sich mit der Verarbeitung befasst (kann sogar die Türen für etwas Sprachunabhängiges öffnen). Was wären in diesem Fall einige beliebte oder häufig verwendete Lösungen mit gevent (d.h. Sellerie)? - Best Practices

Antworten auf die Frage(2)

Ihre Antwort auf die Frage