Ich versuche, einen Python-Webserver mit Django und Waitress zu erstellen, möchte aber wissen, wie Waitress mit gleichzeitigen Anforderungen umgeht und wann Blockierungen auftreten können.
Während in der Waitress-Dokumentation erwähnt wird, dass mehrere Worker-Threads verfügbar sind, enthält sie nicht viele Informationen darüber, wie sie implementiert sind und wie sich die Python-GIL auf sie auswirkt (Hervorhebung meiner eigenen):
Wenn ein Kanal feststellt, dass der Client mindestens eine vollständig gültige HTTP-Anforderung gesendet hat, plant er eine "Aufgabe" mit einem "Thread-Dispatcher". Der Thread-Dispatcher verwaltet einen festen Pool von Worker-Threads, die für die Client-Arbeit verfügbar sind (standardmäßig 4 Threads). Wenn ein Arbeitsthread verfügbar ist, wenn eine Aufgabe geplant ist, führt der Arbeitsthread die Aufgabe aus. Die Task hat Zugriff auf den Kanal und kann in den Ausgabepuffer des Kanals zurückschreiben. Wenn alle Arbeitsthreads verwendet werden , warten geplante Aufgaben in einer Warteschlange darauf, dass ein Arbeitsthread verfügbar wird.
Es scheint auch nicht viele Informationen über Stackoverflow zu geben. Aus der Frage "Ist Gunicorns gthread asynchroner Arbeiter analog zu Kellnerin?" ::
Die Kellnerin verfügt über einen asynchronen Master-Thread, der Anforderungen puffert und jede Anforderung nach Abschluss der Anforderungs-E / A in einen ihrer Sync-Worker-Threads einreiht.
Diese Aussagen richten sich nicht an die GIL (zumindest nach meinem Verständnis), und es wäre großartig, wenn jemand näher darauf eingehen könnte, wie Arbeitsthreads für Waitress funktionieren. Vielen Dank!
Antworten:
So funktionieren die ereignisgesteuerten asynchronen Server im Allgemeinen:
Ziemlich genau so, wie ich es oben beschrieben habe. Und für Arbeiter werden Threads erstellt, keine Prozesse.
Kellnerin verwendet Threads für Arbeiter. Ja, sie sind von GIL betroffen, da sie nicht wirklich gleichzeitig sind, obwohl sie zu sein scheinen. "Asynchron" ist der richtige Begriff.
Threads in Python werden in einem einzelnen Prozess auf einem einzelnen CPU-Kern ausgeführt und nicht parallel. Ein Thread erfasst die GIL für eine sehr kurze Zeit und führt seinen Code aus. Anschließend wird die GIL von einem anderen Thread erfasst.
Da die GIL jedoch für Netzwerk-E / A freigegeben wird, erfasst der übergeordnete Prozess die GIL immer dann, wenn ein Netzwerkereignis (z. B. eine eingehende Anforderung) vorliegt. Auf diese Weise können Sie sicher sein, dass die GIL die netzwerkgebundenen Vorgänge nicht beeinträchtigt ( wie das Empfangen von Anfragen oder das Senden von Antworten).
Auf der anderen Seite sind Python-Prozesse tatsächlich gleichzeitig: Sie können auf mehreren Kernen parallel ausgeführt werden. Die Kellnerin verwendet jedoch keine Prozesse.
Solltest du dir Sorgen machen?
Wenn Sie nur kleine Blockierungsaufgaben wie das Lesen / Schreiben von Datenbanken ausführen und nur einige hundert Benutzer pro Sekunde bedienen, ist die Verwendung von Threads nicht wirklich schlecht.
Wenn Sie eine große Anzahl von Benutzern bedienen oder lange laufende Blockierungsaufgaben ausführen möchten, können Sie externe Aufgabenwarteschlangen wie Sellerie verwenden . Dies ist viel besser als das Laichen und Verwalten von Prozessen selbst.
quelle