Gunicorn und Python GIL in einem Artikel verstehen

WBOY
Freigeben: 2023-04-12 10:40:10
nach vorne
1230 Leute haben es durchsucht

Gunicorn und Python GIL in einem Artikel verstehen

Was ist die Python-GIL, wie funktioniert sie und wie wirkt sie sich auf Gunicorn aus?

Welchen Gunicorn-Arbeitertyp sollte ich für die Produktionsumgebung wählen?

Python verfügt über eine globale Sperre (GIL), die nur die Ausführung eines Threads zulässt (d. h. Bytecode interpretieren). Meiner Meinung nach ist es wichtig zu verstehen, wie Python mit Parallelität umgeht, wenn Sie Ihre Python-Dienste optimieren möchten.

Python und Gunicorn bieten Ihnen unterschiedliche Möglichkeiten, mit Parallelität umzugehen, und da es kein Allheilmittel gibt, das alle Anwendungsfälle abdeckt, ist es eine gute Idee, die Optionen, Kompromisse und Vorteile jeder Option zu verstehen.

Gunicorn-Arbeitertypen

Gunicorn stellt diese verschiedenen Optionen unter dem Konzept der „Arbeitertypen“ dar. Jeder Typ ist für eine bestimmte Reihe von Anwendungsfällen geeignet.

  • sync——Teilen Sie den Prozess in N parallel laufende Prozesse auf, um ihn zu verarbeiten die Anfrage.
  • gthread——Generieren Sie N Threads, um Anfragen gleichzeitig zu bearbeiten.
  • eventlet/gevent – ​​Erzeugen Sie grüne Threads, um gleichzeitige Anfragen zu bedienen.

Gunicorn Sync Worker

Dies ist die einfachste Art von Job, bei dem die einzige Parallelitätsoption darin besteht, N Prozesse zu forken und diese parallel auszuführen lokale Serviceanfrage.

Sie können gut funktionieren, verursachen aber viel Overhead (z. B. Speicher- und CPU-Kontextwechsel), und wenn die meiste Zeit Ihrer Anfrage darauf wartet, dass ich/ O, dann ist die Skalierbarkeit nicht gut.

Gunicorn gthread worker

gthread worker verbessert dies, indem es Ihnen ermöglicht, N Threads pro Prozess zu erstellen. Dies verbessert die E/A-Leistung, da Sie mehr Instanzen Ihres Codes gleichzeitig ausführen können. Dies ist der einzige der vier Fälle, der von GIL betroffen ist. #?? Verbessern Sie das Gthread-Modell weiter. Dadurch erhalten Sie Tausende dieser Greenlets zu einem Bruchteil der Kosten im Vergleich zu System-Threads. Ein weiterer Unterschied besteht darin, dass es eher einem kollaborativen als einem präventiven Arbeitsmodell folgt und eine ununterbrochene Arbeit ermöglicht, bis sie blockiert werden. Wir analysieren zunächst das Verhalten des Gthread-Worker-Threads bei der Verarbeitung von Anfragen und wie es durch die GIL beeinflusst wird.

Im Gegensatz zur Synchronisierung, bei der jede Anfrage direkt von einem Prozess bedient wird, verfügt bei gthread jeder Prozess über N Threads, um eine bessere Skalierung zu ermöglichen, ohne dass der Overhead mehrerer Prozesse anfällt. Da Sie mehrere Threads im selben Prozess ausführen, verhindert die GIL, dass sie parallel ausgeführt werden.

GIL ist kein Prozess oder spezieller Thread. Es handelt sich lediglich um eine boolesche Variable, deren Zugriff durch einen Mutex geschützt ist, der sicherstellt, dass in jedem Prozess nur ein Thread ausgeführt wird. Wie es funktioniert, sehen Sie im Bild oben. In diesem Beispiel können wir sehen, dass zwei Systemthreads gleichzeitig laufen, wobei jeder Thread eine Anfrage bearbeitet. Der Prozess ist wie folgt: Thread A hält die GIL und beginnt mit der Bearbeitung der Anfrage.

Nach einer Weile versucht Thread B, die Anfrage zu bedienen, kann die GIL jedoch nicht halten. B Legen Sie ein Timeout fest, um die Freigabe der GIL zu erzwingen, wenn dies nicht vor Erreichen des Timeouts geschieht.

A Die GIL wird erst freigegeben, wenn das Timeout erreicht ist. B setzt das Flag gil_drop_request, um A zu zwingen, die GIL sofort freizugeben.

    A gibt die GIL frei und wartet, bis ein anderer Thread die GIL ergreift, um die Situation zu vermeiden, in der A die GIL weiterhin freigibt und ergreift, ohne dass andere Threads sie ergreifen können.
  • B beginnt zu laufen.
  • B Gibt die GIL frei und blockiert gleichzeitig E/A.
  • A beginnt zu laufen.
  • B versuchte noch einmal zu laufen, wurde aber suspendiert.
  • A Abgeschlossen, bevor die Zeitüberschreitung erreicht ist.
  • B Lauf abgeschlossen.
  • Gleiches Szenario, aber mit gevent 🎜#
  • Eine weitere Option zur Erhöhung der Parallelität ohne Verwendung von Prozessen ist die Verwendung von Grünlinge. Dieser Worker erzeugt „Benutzer-Threads“ anstelle von „System-Threads“, um die Parallelität zu erhöhen.
  • Das bedeutet zwar, dass sie nicht von der GIL betroffen sind, es bedeutet aber auch, dass Sie die Parallelität immer noch nicht erhöhen können, da sie von der CPU nicht parallel geplant werden können.

    • Greenlet A wird so lange ausgeführt, bis ein E/A-Ereignis auftritt oder die Ausführung abgeschlossen ist.
    • Greenlet B wartet, bis Greenlet A die Ereignisschleife freigibt.
    • A ist vorbei.
    • B beginnt.
    • B gibt die Ereignisschleife frei, um auf E/A zu warten.
    • B abgeschlossen.

    In diesem Fall ist es offensichtlich, dass es nicht ideal ist, einen Greenlet-Arbeiter zu haben. Am Ende wartet die zweite Anfrage, bis die erste Anfrage abgeschlossen ist, und wartet dann wieder im Leerlauf auf E/A.

    In diesen Szenarien glänzt das Greenlet-Kollaborationsmodell wirklich, weil Sie keine Zeit mit Kontextwechseln verschwenden und den Aufwand für die Ausführung mehrerer Systemthreads vermeiden.

    Das werden wir im Benchmark-Test am Ende dieses Artikels erleben. Da stellt sich nun die folgende Frage:

    • Wird sich die Änderung des Zeitlimits für den Thread-Kontextwechsel auf die Dienstlatenz und den Durchsatz auswirken?
    • So wählen Sie zwischen gevent/eventlet und gthread, wenn Sie I/O- und CPU-Arbeit mischen.
    • So wählen Sie die Anzahl der Threads mit gthread worker aus.
    • Sollte ich einfach Sync-Worker verwenden und die Anzahl der gespaltenen Prozesse erhöhen, um die GIL zu vermeiden?

    Um diese Fragen zu beantworten, müssen Sie überwachen, um die erforderlichen Metriken zu erfassen und dann maßgeschneiderte Benchmarks mit denselben Metriken durchzuführen. Es hat keinen Sinn, synthetische Benchmarks auszuführen, die keine Korrelation zu Ihren tatsächlichen Nutzungsmustern aufweisen. Die folgende Grafik zeigt Latenz- und Durchsatzmetriken für verschiedene Szenarien, um Ihnen eine Vorstellung davon zu geben, wie alles zusammenwirkt.

    Benchmarking des GIL-Switching-Intervalls

    Gunicorn und Python GIL in einem Artikel verstehenHier können wir sehen, wie sich die Änderung des GIL-Thread-Switching-Intervalls/Timeouts auf die Anforderungslatenz auswirkt. Wie erwartet wird die E/A-Latenz mit abnehmendem Switch-Intervall besser. Dies liegt daran, dass CPU-gebundene Threads gezwungen sind, die GIL häufiger freizugeben und anderen Threads die Möglichkeit zu geben, ihre Arbeit abzuschließen.

    Aber das ist kein Allheilmittel. Durch die Reduzierung des Wechselintervalls dauert die Fertigstellung CPU-gebundener Threads länger. Wir können auch einen Anstieg der Gesamtlatenz und einen Rückgang der Zeitüberschreitungen aufgrund des erhöhten Overheads durch den ständigen Thread-Wechsel feststellen. Wenn Sie es selbst ausprobieren möchten, können Sie das Umschaltintervall mit dem folgenden Code ändern:

    Gunicorn und Python GIL in einem Artikel verstehen

    Benchmarking der Gthread- und Gevent-Latenz mithilfe von CPU-gebundenen Anforderungen

    Gunicorn und Python GIL in einem Artikel verstehen

    Insgesamt können wir sehen, dass der Benchmark die Intuition widerspiegelt abgeleitet aus unserer vorherigen Analyse der Funktionsweise von GIL-gebundenen Threads und Greenlets.

    gthread hat eine bessere durchschnittliche Latenz für IO-gebundene Anfragen, da die Wechselintervalle lang laufende Threads zur Freigabe zwingen.

    gevent CPU-gebundene Anfragen haben eine bessere Latenz als gthread, da sie nicht unterbrochen werden, um andere Anfragen zu bearbeiten.

    Benchmarking des Durchsatzes von gthread vs. gevent unter Verwendung CPU-gebundener Anfragen

    Gunicorn und Python GIL in einem Artikel verstehen

    Die Ergebnisse hier spiegeln auch unsere frühere Annahme wider, dass gevent einen besseren Durchsatz als gthread hat. Diese Benchmarks hängen stark von der Art der durchgeführten Arbeit ab und lassen sich nicht unbedingt direkt auf Ihren Anwendungsfall übertragen.

    Das Hauptziel dieser Benchmarks besteht darin, Ihnen eine Anleitung zu geben, was Sie testen und messen müssen, um jeden CPU-Kern zu maximieren, der Anfragen bedient.

    Da Sie bei allen Gunicorn-Workern die Anzahl der auszuführenden Prozesse angeben können, ändert sich die Art und Weise, wie jeder Prozess gleichzeitige Verbindungen verarbeitet. Achten Sie daher darauf, die gleiche Anzahl an Arbeitskräften einzusetzen, um den Test fair zu gestalten. Versuchen wir nun, die vorherige Frage anhand der aus unserem Benchmark gesammelten Daten zu beantworten.

    Wird sich die Änderung des Zeitlimits für den Thread-Kontextwechsel auf die Dienstlatenz und den Durchsatz auswirken?

    In der Tat. Für die überwiegende Mehrheit der Workloads stellt dies jedoch keinen entscheidenden Faktor dar.

    Wie wähle ich zwischen gevent/eventlet und gthread, wenn ich mit gemischten I/Os und CPUs arbeite? Wie wir sehen können, ermöglicht Ghtread tendenziell eine bessere Parallelität, wenn Sie CPU-intensivere Arbeit haben.

    Wie wähle ich die Anzahl der Threads für den Gthread-Worker aus?

    Solange Ihre Benchmarks ein produktionsähnliches Verhalten simulieren können, werden Sie die Spitzenleistung deutlich erkennen und dann aufgrund zu vieler Threads nachlassen.

    Sollte ich einfach Sync-Worker verwenden und die Anzahl der gespaltenen Prozesse erhöhen, um die GIL zu vermeiden?

    Sofern Ihr I/O nicht fast Null ist, ist die Skalierung nur mit Prozessen nicht die beste Option.

    Fazit

    Coroutinen/Greenlets können die CPU-Effizienz verbessern, da sie Interrupts und Kontextwechsel zwischen Threads vermeiden. Coroutinen tauschen Latenz gegen Durchsatz.

    Wenn Sie IO- und CPU-gebundene Endpunkte mischen, können Coroutinen zu unvorhersehbareren Latenzen führen – CPU-gebundene Endpunkte werden nicht unterbrochen, um andere eingehende Anfragen zu bearbeiten. Wenn Sie sich die Zeit nehmen, gunicorn richtig zu konfigurieren, ist die GIL kein Problem.

Das obige ist der detaillierte Inhalt vonGunicorn und Python GIL in einem Artikel verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:51cto.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!