Wie viele gleichzeitige Anforderungen erhält ein einzelner Flask-Prozess?

137

Ich baue eine App mit Flask, aber ich weiß nicht viel über WSGI und die HTTP-Basis Werkzeug. Wenn ich anfange, eine Flask-Anwendung mit Gunicorn und 4 Worker-Prozessen zu bedienen, bedeutet dies, dass ich 4 gleichzeitige Anfragen bearbeiten kann?

Ich meine gleichzeitige Anfragen und keine Anfragen pro Sekunde oder irgendetwas anderes.

Carson
quelle

Antworten:

182

Wenn Sie den Entwicklungsserver ausführen - was Sie durch Ausführen erhalten app.run()- erhalten Sie einen einzelnen synchronen Prozess, was bedeutet, dass höchstens 1 Anforderung gleichzeitig verarbeitet wird.

Wenn Sie Gunicorn in seiner Standardkonfiguration davor halten und einfach die Anzahl erhöhen --workers, erhalten Sie im Wesentlichen eine Reihe von Prozessen (von Gunicorn verwaltet), die sich jeweils wie der app.run()Entwicklungsserver verhalten . 4 Arbeiter == 4 gleichzeitige Anfragen. Dies liegt daran, dass Gunicorn standardmäßig den enthaltenen syncArbeitertyp verwendet.

Es ist wichtig anzumerken, dass Gunicorn auch asynchrone Arbeiter umfasst, nämlich eventletund gevent(und auch tornado, aber das scheint am besten mit dem Tornado-Framework verwendet zu werden). Wenn Sie einen dieser Async-Worker mit dem --worker-classFlag angeben, erhalten Sie Gunicorn, das eine Reihe von Async-Prozessen verwaltet, von denen jeder seine eigene Parallelität verwaltet. Diese Prozesse verwenden keine Threads, sondern Coroutinen. Grundsätzlich kann in jedem Prozess immer noch nur 1 Ereignis gleichzeitig ausgeführt werden (1 Thread), aber Objekte können angehalten werden, wenn sie auf den Abschluss externer Prozesse warten (z. B. Datenbankabfragen oder Warten auf Netzwerk-E / A).

Wenn Sie also einen der asynchronen Mitarbeiter von Gunicorn verwenden, kann jeder Mitarbeiter mehr als eine einzelne Anfrage gleichzeitig bearbeiten. Wie viele Mitarbeiter am besten geeignet sind, hängt von der Art Ihrer App, ihrer Umgebung, der Hardware usw. ab. Weitere Informationen finden Sie auf der Design- Seite von Gunicorn und Hinweise zur Funktionsweise von gevent auf der Intro-Seite.

Ryan Artecona
quelle
4
Gunicorn unterstützt seit Version 19 "echte" Threads. Sehen Sie dies und das .
Filipe Correia
2
Wie verfolgt man, welche Ressourcen gemeinsam genutzt werden (und wie) und welche zwischen Threads / Prozessen vollständig getrennt sind? Wie würde ich beispielsweise mit einer Situation umgehen, in der ich eine riesige Datenstruktur zwischen mehreren Prozessen teilen möchte, die von Gunicorn verarbeitet und in den Flask-Handlern verwendet werden?
Johann Petrak
Was Sie @Johsm fragen, ist wie zu fragen, wie Daten zwischen verschiedenen Prozessen innerhalb des Betriebssystems ausgetauscht werden. Die Antwort darauf kann Ihre Frage beantworten. Sie müssen externen Speicher verwenden, da Prozesse ihren Speicher nicht mit anderen Prozessen teilen. Gunicorn ist nur hier, um Multiprozessor-CPU-Architekturen zu verwenden, behandelt diese Probleme jedoch nicht.
Adkl
Was ist mit Eva? Gilt das auch für Eva?
Eswar
2
Der Flask Development Server verwendet standardmäßig Threads seit v1.0 ( github.com/pallets/flask/pull/2529 )
Hychou
40

Derzeit gibt es eine weitaus einfachere Lösung als die bereits bereitgestellten. Wenn Sie Ihre Anwendung ausführen, müssen Sie nur den threaded=TrueParameter an den app.run()Aufruf übergeben, wie:

app.run(host="your.host", port=4321, threaded=True)

Eine weitere Option gemäß den Angaben in den werkzeug-Dokumenten ist die Verwendung des processesParameters, der eine Zahl> 1 erhält, die die maximale Anzahl gleichzeitiger Prozesse angibt, die verarbeitet werden sollen:

  • Threaded - Sollte der Prozess jede Anforderung in einem separaten Thread behandeln?
  • Prozesse - Wenn größer als 1, wird jede Anforderung in einem neuen Prozess bis zu dieser maximalen Anzahl gleichzeitiger Prozesse verarbeitet.

Etwas wie:

app.run(host="your.host", port=4321, processes=3) #up to 3 processes

Weitere Informationen zur run()Methode hier und zum Blog-Beitrag , der mich dazu brachte, die Lösung und API-Referenzen zu finden.


Hinweis: In den Flask-Dokumenten zu den run()Methoden wird darauf hingewiesen, dass von der Verwendung in einer Produktionsumgebung abgeraten wird, da ( Zitat ): "Der integrierte Server von Flask ist zwar leicht und benutzerfreundlich, eignet sich jedoch nicht für die Produktion, da er nicht gut skaliert werden kann . "

Sie verweisen jedoch auf die Seite Bereitstellungsoptionen, um die empfohlenen Möglichkeiten für die Produktion zu finden.

DarkCygnus
quelle
5
Danke für die Information. Es ist wichtig zu beachten, dass das Dokument für die Ausführung besagt, dass es nicht in einer Produktionsumgebung verwendet werden sollte, in der angegeben wird, dass es die Sicherheits- oder Leistungsanforderungen nicht erfüllt.
Coffee_fan
1
@Coffee_fan du hast recht. Selbst in der neuesten Version 1.1.x raten sie davon ab und schlagen stattdessen vor, ihre Seite mit den Bereitstellungsoptionen zu überprüfen, wenn sie in die Produktion gehen. Einschließlich Ihrer wertvollen Beobachtung in der Antwort :)
DarkCygnus
33

Flask verarbeitet gleichzeitig eine Anfrage pro Thread. Wenn Sie 2 Prozesse mit jeweils 4 Threads haben, sind das 8 gleichzeitige Anforderungen.

Flask erzeugt oder verwaltet keine Threads oder Prozesse. Das ist die Verantwortung des WSGI-Gateways (z. B. Gunicorn).

jd.
quelle
9

Nein, mit mehr kann man definitiv umgehen.

Es ist wichtig, sich daran zu erinnern, dass die CPU tief im Inneren, wenn Sie einen Single-Core-Computer ausführen, wirklich immer nur einen Befehl * gleichzeitig ausführt.

Die CPU kann nämlich nur einen sehr begrenzten Satz von Befehlen ausführen, und sie kann nicht mehr als einen Befehl pro Takt-Tick ausführen (viele Befehle benötigen sogar mehr als einen Tick).

Daher ist die meiste Parallelität, über die wir in der Informatik sprechen, Software-Parallelität. Mit anderen Worten, es gibt Ebenen der Softwareimplementierung, die die CPU der untersten Ebene von uns abstrahieren und uns glauben lassen, dass wir gleichzeitig Code ausführen.

Diese "Dinge" können Prozesse sein, bei denen es sich um Codeeinheiten handelt, die gleichzeitig in dem Sinne ausgeführt werden, dass jeder Prozess glaubt, in seiner eigenen Welt mit seinem eigenen, nicht gemeinsam genutzten Speicher ausgeführt zu werden.

Ein weiteres Beispiel sind Threads, bei denen es sich um Codeeinheiten innerhalb von Prozessen handelt, die ebenfalls Parallelität ermöglichen.

Der Grund, warum Ihre 4 Worker-Prozesse mehr als 4 Anforderungen verarbeiten können, besteht darin, dass sie Threads auslösen, um mehr und mehr Anforderungen zu verarbeiten.

Das tatsächliche Anforderungslimit hängt vom ausgewählten HTTP-Server, E / A, Betriebssystem, Hardware, Netzwerkverbindung usw. ab.

Viel Glück!

* Anweisungen sind die grundlegenden Befehle, die die CPU ausführen kann. Beispiele - Fügen Sie zwei Zahlen hinzu und springen Sie von einer Anweisung zur nächsten

user1094786
quelle
1
Ist es Gunicorn, das die Fäden oder die Flasche hervorbringt? Ich fand keine Beweise für eine der beiden Möglichkeiten.
jd.
1
Klar, ich verstehe das über die Prozesse, aber die Antwort besagt, dass nach Bedarf mehr Threads erzeugt werden. Dafür hätte ich gerne eine Bestätigung.
jd.
4
"Tief im Inneren führt die CPU unter der Annahme, dass Sie einen Single-Core-Computer ausführen, immer nur einen Befehl * gleichzeitig aus." Dies ist auf modernen Computern nicht korrekt. Die meisten modernen CPUs sind Pipeline- und Superskalar- CPUs , bei denen sogar ein einzelner Kern mehrere Ausführungseinheiten und einen Befehlsdecoder aufweist, der den von der Softwareseite aus gesehenen "Maschinencode" in die tatsächlichen Hardware-Mikrooperationen konvertiert, die an die einzelnen Ausführungseinheiten gesendet werden.
Michael Geary
1
Zur Verdeutlichung haben CPUs vor langer Zeit die numerischen Anweisungen in einer ausführbaren Datei - dem Maschinencode - direkt ausgeführt. Jede CPU-Referenz hatte ein Befehlszeitdiagramm, das zeigte, wie viele Taktzyklen jeder Befehl einschließlich etwaiger Speicherreferenzen benötigte. Sie können also einfach die Zeitangaben addieren, um zu wissen, wie lange ein Code dauern würde. Moderne CPUs sind überhaupt nicht so. Eine interessante Ausnahme ist der BeagleBone mit einem modernen superskalaren ARM-Prozessor und zwei altmodischen "PRU" -Prozessoren mit festem Befehlszeitpunkt.
Michael Geary
1
Und um das zu verdeutlichen , als ich "modern" sagte, benutzte ich es als lose Abkürzung für Prozessoren wie ARM / Intel / AMD-Chips - Pipeline, Superskalar usw. Natürlich gibt es auch moderne Prozessoren, die auf die alte Art und Weise mit festem Timing arbeiten gemäß Anweisung, wie die von mir erwähnten BeagleBone-PRUs und verschiedene neue Mikrocontroller. (Und jetzt zurück zu Gunicorn!)
Michael Geary