Warum wurde Python mit der GIL geschrieben?

Die globale Interpreter-Sperre (GIL) scheint häufig als Hauptgrund dafür angeführt zu werden, dass Threading und dergleichen in Python schwierig ist – was die Frage aufwirft „Warum wurde das überhaupt gemacht?“

Da ich kein Programmierer bin, habe ich keine Ahnung, warum das so sein könnte – was war die Logik hinter dem Einfügen der GIL?

Kommentare

  • Der Wikipedia-Artikel besagt, dass “ Die GIL kann ein erhebliches Hindernis für die Parallelität sein – ein Preis, der für die Dynamik der Sprache “ gezahlt wird, und sagt weiter, dass “ Gründe für die Verwendung einer solchen Sperre sind: Erhöhte Geschwindigkeit von Single-Thread-Programmen (keine Notwendigkeit, Sperren für alle Datenstrukturen separat zu erwerben oder freizugeben) und einfache Integration von C-Bibliotheken, die normalerweise vorhanden sind nicht threadsicher. “
  • @RobertHarvey, Dynamik hat nichts zu tun damit. Das Problem ist die Mutation.
  • stackoverflow.com/questions/265687/…
  • Kann ‚ nicht anders, als das Gefühl zu haben, dass Java ‚ keine vorzeichenlosen Zahlen enthält, um Menschen zu verhindern, die sich nicht anziehen ‚ weiß nicht, was sie tun ‚ sich selbst in den Fuß zu schießen. Leider bekommt jeder, der weiß, was er ‚ tut, eine mangelhafte Sprache, was wirklich schade ist, weil Python auf so viele andere Arten rockt
  • @Basic Es muss eine Standardmethode geben, um mit Byte-Arrays in Java umzugehen (ich habe sie ‚ schon lange nicht mehr verwendet), um Krypto-Mathematik zu betreiben. Python (zum Beispiel) hat ‚ keine signierten Nummern, aber ich würde ‚ nicht einmal versuchen, bitweise Operationen damit durchzuführen, weil es solche gibt Bessere Möglichkeiten.

Antwort

Es gibt verschiedene Implementierungen von Python, z. B. CPython, IronPython, RPython, usw.

Einige von ihnen haben eine GIL, andere nicht. CPython hat beispielsweise die GIL:

Von http://en.wikipedia.org/wiki/Global_Interpreter_Lock

Anwendungen, die in Programmiersprachen mit einer GIL geschrieben wurden, können so gestaltet werden, dass separate Prozesse verwendet werden, um eine vollständige Parallelität zu erreichen, da jeder Prozess seinen eigenen Interpreter und hat hat wiederum eine eigene GIL.

Vorteile der GIL

  • Erhöhte Geschwindigkeit von Single-Thread-Programmen.
  • Einfache Integration von C-Bibliotheken, die normalerweise nicht threadsicher sind.

Warum Python (CPython und andere) die GIL

In CPython ist die globale Interpretersperre (GIL) ein Mutex, der verhindert, dass mehrere native Threads gleichzeitig Python-Bytecodes ausführen. Diese Sperre ist hauptsächlich erforderlich, weil die Speicherverwaltung von CPython nicht threadsicher ist.

Die GIL ist umstritten, da sie verhindert, dass Multithread-CPython-Programme in bestimmten Situationen die Vorteile von Multiprozessorsystemen voll ausnutzen Langzeitoperationen wie E / A, Bildverarbeitung und NumPy-Nummernverarbeitung finden außerhalb der GIL statt. Daher wird die GIL nur in Multithread-Programmen, die viel Zeit in der GIL verbringen und CPython-Bytecode interpretieren, zu einer GIL Engpass.

Python hat aus mehreren Gründen eine GIL im Gegensatz zu feinkörnigem Sperren:

  • Im Single-Thread-Fall ist es schneller.

  • Im Fall von Multithreads für E / A-gebundene Programme ist dies schneller.

  • Im Fall von Multithreads für Programme mit CPU-Bindung ist dies schneller ihre rechenintensive Arbeit in C-Bibliotheken.

  • Es macht C-Erweiterungen sind einfacher zu schreiben: Es gibt keinen Wechsel der Python-Threads, es sei denn, Sie lassen dies zu (d. H. zwischen den Makros Py_BEGIN_ALLOW_THREADS und Py_END_ALLOW_THREADS).

  • Dies erleichtert das Umschließen von C-Bibliotheken. Sie müssen sich keine Sorgen um die Thread-Sicherheit machen. Wenn die Bibliothek nicht thread-sicher ist, lassen Sie die GIL einfach gesperrt, während Sie sie aufrufen.

Die GIL kann von C-Erweiterungen freigegeben werden. Die Standardbibliothek von Python gibt die GIL für jeden blockierenden E / A-Aufruf frei. Somit hat die GIL keine Konsequenzen für die Leistung von E / A-gebundenen Servern. Sie können also Netzwerkserver in Python mithilfe von Prozessen (Fork), Threads oder asynchronen E / A erstellen, und die GIL wird Ihnen nicht im Weg stehen.

Numerische Bibliotheken in C oder Fortran können ebenfalls mit dem aufgerufen werden GIL freigelassen. Während Ihre C-Erweiterung auf den Abschluss einer FFT wartet, führt der Interpreter andere Python-Threads aus.Eine GIL ist somit auch in diesem Fall einfacher und schneller als eine feinkörnige Verriegelung. Dies macht den Großteil der numerischen Arbeit aus. Die NumPy-Erweiterung gibt die GIL nach Möglichkeit frei.

Threads sind normalerweise eine schlechte Methode, um die meisten Serverprogramme zu schreiben. Wenn die Last niedrig ist, ist das Gabeln einfacher. Wenn die Last hoch ist, ist eine asynchrone E / A- und ereignisgesteuerte Programmierung (z. B. mit dem Twisted Framework von Python) besser. Die einzige Entschuldigung für die Verwendung von Threads ist das Fehlen von os.fork unter Windows.

Die GIL ist genau dann ein Problem, wenn Sie CPU-intensive Arbeit in reinem Python ausführen. Hier können Sie ein saubereres Design mithilfe von Prozessen und Nachrichtenübermittlung (z. B. mpi4py) erzielen. Es gibt auch ein „Verarbeitungs“ -Modul in Python-Käse Shop, der Prozessen die gleiche Schnittstelle wie Threads gibt (dh Threading ersetzen. Thread durch Verarbeitung. Prozess).

Threads können verwendet werden, um die Reaktionsfähigkeit einer GUI unabhängig von der GIL aufrechtzuerhalten. Wenn die GIL Ihre Leistung beeinträchtigt (vgl. die obige Diskussion), können Sie Ihren Thread einen Prozess erzeugen lassen und warten, bis er abgeschlossen ist.

Kommentare

  • Klingt nach sauren Trauben Python kann ‚ Threads nicht richtig ausführen, sodass Sie Gründe dafür finden, warum Threads unnötig oder sogar schlecht sind. “ Wenn die Last ist niedrig, fo rking ist einfacher „, ernsthaft? Und die GIL ist “ schneller “ für all diese Fälle nur, wenn Sie darauf bestehen, Referenzzähl-GC zu verwenden.
  • s/RPython/PyPy/g. @MichaelBorgwardt Gründe für GIL anzugeben ist eine Art Punkt der Frage, nicht wahr ‚? Obwohl ich zustimmen würde, dass ein Teil des Inhalts dieser Antwort (nämlich die Diskussion von Alternativen) nebensächlich ist. Und zum Guten oder zum Schlechten ist das Nachzählen jetzt fast unmöglich loszuwerden – es ist tief in der gesamten API und Codebasis verwurzelt; ‚ ist fast unmöglich, es loszuwerden, ohne den halben Code neu zu schreiben und den gesamten externen Code zu beschädigen.
  • Don ‚ Vergessen Sie nicht die Bibliothek multiprocessing – Standard seit 2.6. Die Worker-Pools von ‚ sind eine superschnelle Abstraktion für einige einfache Arten von Parallelität.
  • @alcalde Nur wenn Sie ‚ weiß nicht, was Sie ‚ tun, und / oder Sie ‚ möchten nicht, dass Ihre Threads kooperativ arbeiten können / kommunizieren. Andernfalls ist es ‚ ein königlicher Schmerz auf der Rückseite, insbesondere angesichts des Overheads, einen neuen Prozess auf einigen Betriebssystemen zu starten. Wir haben Server mit 32 Kernen. Um sie in CPython vollständig nutzen zu können, benötige ich ‚ 32 Prozesse. Das ‚ ist keine “ gute Lösung “ es ‚ ist ein Hack, um die Unzulänglichkeiten von CPython ‚ zu umgehen.
  • Die Tatsache, dass Threads auf anderen Plattformen als Windows vorhanden sind, sollte der Beweis genug sein, dass das Gabeln nicht funktioniert ‚ ist nicht in jeder Situation ausreichend.

Antwort

Zuerst aus: Python hat keine GIL. Python ist eine Programmiersprache. Eine Programmiersprache besteht aus einer Reihe abstrakter mathematischer Regeln und Einschränkungen. Die Python-Sprachspezifikation enthält nichts, was besagt, dass es eine GIL geben muss.

Es gibt viele verschiedene Implementierungen von Python. Einige haben eine GIL, andere nicht.

Eine einfache Erklärung für eine GIL ist, dass das Schreiben von gleichzeitigem Code schwierig ist. Indem Sie eine riesige Sperre um Ihren Code setzen, erzwingen Sie, dass dieser immer seriell ausgeführt wird. Problem gelöst!

Insbesondere in CPython besteht ein wichtiges Ziel darin, die Erweiterung des Interpreters um in C geschriebene Plugins zu vereinfachen. Auch hier ist das Schreiben von gleichzeitigem Code schwierig, da garantiert wird, dass es keinen gibt Parallelität erleichtert das Schreiben von Erweiterungen für den Interpreter. Außerdem sind viele dieser Erweiterungen nur dünne Wrapper um vorhandene Bibliotheken, die möglicherweise nicht unter Berücksichtigung der Parallelität geschrieben wurden.

Kommentare

  • Das ‚ ist das gleiche Argument wie Java ‚ das Fehlen vorzeichenloser numerischer Typen – die Entwickler denken, dass alle anderen dümmer sind als sie …
  • @Basic – ob Sie es glauben oder nicht, selbst wenn Sie ‚ nicht wirklich, wirklich dumm sind, stellt sich heraus, dass eine Sprache vereinfachende Annahmen enthält, die bedeuten, dass Sie nicht ‚ über bestimmte Dinge nicht nachzudenken, damit sie funktionieren, ist immer noch eine nützliche Sache.CPython eignet sich hervorragend für bestimmte Dinge, einschließlich einfacher Multithread-Anwendungen (bei denen das Programm an E / A gebunden ist, was viele sind, und daher spielt die GIL keine Rolle, da die Entwurfsentscheidungen getroffen wurden) Die GIL, die beste Lösung, erleichtert auch die Programmierung dieser Anwendungen, insbesondere die Tatsache, dass sie atomare Operationen für Sammlungen unterstützt.
  • @Jules Ja, sie ‚ ist sehr praktisch, bis Sie diese Funktionen benötigen. cpython ‚ s “ bevorzugte “ Lösung von “ schreibe es einfach in einer anderen Sprache wie c ++ “ bedeutet dann, dass du jeden einzelnen Python-Vorteil verlierst. Wenn Sie ‚ die Hälfte Ihres Codes in C ++ schreiben, warum dann mit Python beginnen? Sicher, für kleine API / Klebe-Projekte ist es ‚ schnell und einfach, und für ETL ‚ ist es unübertroffen, aber es ‚ ist nicht für Dinge geeignet, die schweres Heben erfordern. Das gleiche wie mit Java, um mit Hardware zu kommunizieren … ‚ ist fast komisch, durch welche Reifen Sie springen müssen.
  • @Basic One of Python ‚ s und damit CPythons ‚ Kernphilosophie ist es, die Technologie “ freundlich und freundlich zu gestalten einfach zu bedienen „. Parallele Programmierung ohne globale Sperre ist nicht das. In Anbetracht der Tatsache, dass es viele Implementierungen ohne GIL gibt, ist es sinnvoll, mindestens eine Implementierung bereitzustellen, die über GIL verfügt.
  • Sie sagen, “ ist es sinnvoll, mindestens bereitzustellen Eine Implementierung, die es hat. “ wie es ‚ ist die offensichtliche Schlussfolgerung, aber keine andere Sprache I ‚ Ich bin mir bewusst, dass seine Entwickler auf diese Weise humpeln, sodass ‚ nicht so offensichtlich sein kann.

Antwort

Was ist der Zweck einer GIL?

In der CAPI-Dokumentation heißt es zu diesem Thema:

Der Python-Interpreter ist nicht vollständig threadsicher . Um Python-Programme mit mehreren Threads zu unterstützen, gibt es eine globale Sperre, die als globale Interpretersperre oder GIL bezeichnet wird und vom aktuellen Thread gehalten werden muss, bevor er sicher auf Python-Objekte zugreifen kann. Ohne die Sperre können selbst die einfachsten Vorgänge Probleme in einem Multithread-Programm verursachen: Wenn beispielsweise zwei Threads gleichzeitig den Referenzzähler desselben Objekts erhöhen, wird der Referenzzähler möglicherweise nur einmal statt zweimal erhöht.

Mit anderen Worten, die GIL verhindert eine Beschädigung des Zustands. Python-Programme sollten niemals einen Segmentierungsfehler erzeugen, da nur speichersichere Operationen zulässig sind. Die GIL erweitert diese Zusicherung auf Multithread-Programme.

Welche Alternativen gibt es?

Wenn der Zweck der GIL darin besteht, den Staat vor Korruption zu schützen, besteht eine offensichtliche Alternative darin, sich auf ein viel feineres Korn festzulegen. vielleicht auf Objektebene. Das Problem dabei ist, dass, obwohl gezeigt wurde, dass es die Leistung von Multithread-Programmen erhöht, es mehr Overhead hat und Single-Thread-Programme darunter leiden.

Kommentare

  • Es wäre großartig, wenn ein Benutzer ein Programm mit einer Interpreter-Option ausführen könnte, die das Gil für eine feinkörnige Sperre ersetzt, und irgendwie schreibgeschützt weiß, ob der aktuelle Prozess mit oder ohne ausgelöst wurde gil.
  • Trotz GIL konnte ich aufgrund der unachtsamen Verwendung des Moduls pyodbc einen Segmentierungsfehler in einem Multithread-Programm erzeugen. Daher sollte “ niemals einen Segmentierungsfehler erzeugen. “ ist ein Irrtum.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.