Waarom is Python geschreven met de GIL?

De globale interpreter lock (GIL) lijkt vaak te worden aangehaald als een belangrijke reden waarom threading en dergelijke een beetje lastig is in Python – wat de vraag oproept “Waarom is dat in de eerste plaats gedaan?”

Omdat ik geen programmeur ben, heb ik geen idee waarom dat zou kunnen zijn – wat was de logica achter het invoeren van de GIL?

Opmerkingen

  • In het Wikipedia-artikel staat dat ” de GIL kan een belangrijke belemmering vormen voor parallellisme – een prijs die wordt betaald voor het hebben van de dynamiek van de taal ” , en gaat verder met te zeggen dat ” Redenen voor het gebruik van een dergelijke vergrendeling zijn onder meer: hogere snelheid van single-threaded programmas (geen noodzaak om vergrendelingen op alle gegevensstructuren afzonderlijk te verwerven of vrij te geven) en eenvoudige integratie van C-bibliotheken die niet thread-safe. ”
  • @RobertHarvey, dynamiek heeft niets te maken ermee. Het probleem is mutatie.
  • stackoverflow.com/questions/265687/…
  • Kan ‘ het gevoel geven dat, net als het gebrek aan niet-ondertekende cijfers van Java ‘, het bedoeld was om te voorkomen dat mensen ‘ weten niet wat ze ‘ doen terwijl ze zichzelf in de voet schieten. Helaas krijgt iedereen die doet weet wat hij ‘ doet, een gebrekkige taal, wat echt jammer is omdat Python op zoveel andere manieren rockt
  • @Basis er moet een standaardmanier zijn om met byte-arrays in Java om te gaan (ik heb het ‘ niet in een lange tijd gebruikt) om crypto-wiskunde te kunnen doen. Python (bijvoorbeeld) heeft geen ‘ t getallen met teken, maar ik zou ‘ zelfs niet proberen om er bitsgewijze bewerkingen mee uit te voeren, omdat er betere manieren.

Answer

Er zijn verschillende implementaties van Python, bijvoorbeeld CPython, IronPython, RPython, etc.

Sommige hebben een GIL, andere niet. CPython heeft bijvoorbeeld de GIL:

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

Toepassingen die zijn geschreven in programmeertalen met een GIL kunnen worden ontworpen om afzonderlijke processen te gebruiken om volledig parallellisme te bereiken, aangezien elk proces zijn eigen interpreter heeft en heeft op zijn beurt zijn eigen GIL.

Voordelen van de GIL

  • Verhoogde snelheid van single-threaded programmas.
  • Eenvoudige integratie van C-bibliotheken die meestal niet thread-safe zijn.

Waarom Python (CPython en anderen) de GIL gebruikt

In CPython is de globale interpreter lock, of GIL, een mutex die voorkomt dat meerdere native threads tegelijk Python-bytecodes uitvoeren. Deze vergrendeling is voornamelijk nodig omdat het geheugenbeheer van CPython niet thread-safe is.

De GIL is controversieel omdat het voorkomt dat multithreaded CPython-programmas in bepaalde situaties ten volle profiteren van multiprocessorsystemen. Merk op dat potentieel blokkerende of Langlopende bewerkingen, zoals I / O, beeldverwerking en NumPy number crunching, gebeuren buiten de GIL. Daarom wordt de GIL alleen in multithreaded-programmas die veel tijd in de GIL doorbrengen en CPython-bytecode interpreteren. bottleneck.

Python heeft een GIL in tegenstelling tot fijnmazige vergrendeling om verschillende redenen:

  • Het is sneller in het geval met één thread.

  • Het is sneller in het geval van multi-threaded voor i / o-gebonden programmas.

  • Het is sneller in het geval van multi-threaded voor cpu-gebonden programmas die hun rekenintensieve werk in C-bibliotheken.

  • Het maakt C-extensies gemakkelijker te schrijven: er zal geen schakelaar van Python-threads zijn, behalve waar u dit toestaat (d.w.z. tussen de Py_BEGIN_ALLOW_THREADS en Py_END_ALLOW_THREADS macros).

  • Het maakt het omwikkelen van C-bibliotheken gemakkelijker. U hoeft zich geen zorgen te maken over draadveiligheid. Als de bibliotheek niet draadveilig is, houdt u de GIL gewoon vergrendeld terwijl u hem oproept.

De GIL kan worden vrijgegeven door C extensies. De standaard bibliotheek van Python geeft de GIL vrij rond elke blokkerende i / o-oproep. De GIL heeft dus geen gevolgen voor de prestaties van i / o-gebonden servers. Je kunt dus netwerkservers in Python maken met behulp van processen (fork), threads of asynchrone i / o, en de GIL zal je niet in de weg zitten.

Numerieke bibliotheken in C of Fortran kunnen op dezelfde manier worden aangeroepen met de GIL vrijgegeven. Terwijl uw C-extensie wacht tot een FFT is voltooid, voert de interpreter andere Python-threads uit.Een GIL is dus ook hier gemakkelijker en sneller dan fijnkorrelige vergrendeling. Dit vormt het grootste deel van het numerieke werk. De NumPy-extensie geeft de GIL vrij waar mogelijk.

Threads zijn meestal een slechte manier om de meeste serverprogrammas te schrijven. Als de belasting laag is, is het vorken gemakkelijker. Als de belasting hoog is, is asynchrone i / o en gebeurtenisgestuurde programmering (bijv. Het gebruik van Pythons Twisted framework) beter. Het enige excuus voor het gebruik van threads is het ontbreken van os.fork op Windows.

De GIL is een probleem als, en alleen als, je CPU-intensief werk doet in pure Python. Hier kun je een schoner ontwerp krijgen met behulp van processen en het doorgeven van berichten (bijv. Mpi4py). Er is ook een “processing” -module in Python-kaas shop, dat processen dezelfde interface geeft als threads (dwz vervang threading.Thread door processing.Process).

Threads kunnen worden gebruikt om de responsiviteit van een GUI te behouden, ongeacht de GIL. Als de GIL uw prestaties schaadt (zie de discussie hierboven), je kunt je thread een proces laten spawnen en wachten tot het klaar is.

Reacties

  • Klinkt als zure druiven voor mij. Python kan ‘ threads niet correct uitvoeren, dus je verzint redenen waarom threads niet nodig of zelfs slecht zijn. ” Als de belasting is laag, fo is rking gemakkelijker “, serieus? En de GIL is ” sneller ” voor al die gevallen, alleen als je erop staat GC voor het tellen van referenties te gebruiken.
  • s/RPython/PyPy/g. @MichaelBorgwardt Redenen geven pro GIL is een beetje het punt van de vraag, is het niet ‘ niet? Hoewel ik het ermee eens ben dat een deel van de inhoud van dit antwoord (namelijk de bespreking van alternatieven) niet ter zake doet. En voor beter of slechter, opnieuw tellen is nu bijna onmogelijk om er vanaf te komen – het zit diep geworteld in de hele API en codebasis; het ‘ is bijna onmogelijk om er vanaf te komen zonder de helft van de code te herschrijven en alle externe code te breken.
  • Don ‘ vergeet de multiprocessing bibliotheek – standaard sinds 2.6. Het ‘ s werkerspools zijn een supergladde abstractie voor enkele eenvoudige soorten parallellisme.
  • @alcalde Alleen als je ‘ weet niet wat u ‘ aan het doen bent en / of u wilt niet ‘ niet willen dat uw threads samenwerken / communiceren. Anders is het ‘ een koninklijke pijn in de rug, vooral gezien de overhead van het starten van een nieuw proces op sommige besturingssystemen. We hebben servers met 32 cores, dus om ze volledig te gebruiken in CPython heb ik ‘ 32 processen nodig. Dat ‘ is geen ” goede oplossing ” het ‘ een hack om CPython ‘ s tekortkomingen te omzeilen.
  • Het feit dat threads bestaan op andere platforms dan Windows zou voldoende moeten bewijzen dat forking niet ‘ t adequaat in elke situatie.

Antwoord

Eerst off: Python heeft geen GIL. Python is een programmeertaal. Een programmeertaal is een verzameling abstracte wiskundige regels en beperkingen. Er staat niets in de Python-taalspecificatie dat zegt dat er een GIL moet zijn.

Er zijn veel verschillende implementaties van Python. Sommige hebben een GIL, andere niet.

Een eenvoudige verklaring voor het hebben van een GIL is dat het schrijven van gelijktijdige code moeilijk is. Door een gigantisch slot om uw code te plaatsen, dwingt u deze altijd serieel te draaien. Probleem opgelost!

Met name in CPython is een belangrijk doel om het gemakkelijk te maken om de interpreter uit te breiden met plug-ins geschreven in C. Nogmaals, het schrijven van gelijktijdige code is moeilijk, dus door te garanderen dat er geen concurrency, het maakt het gemakkelijker om extensies voor de tolk te schrijven. Bovendien zijn veel van die extensies slechts dunne wikkels rond bestaande bibliotheken die misschien niet zijn geschreven met het oog op gelijktijdigheid.

Opmerkingen

  • Dat ‘ s hetzelfde argument als Java ‘ s gebrek aan niet-ondertekende numerieke typen – de ontwikkelaars denken dat alle anderen dommer zijn dan zij …
  • @Basic – geloof het of niet, zelfs als je ‘ niet echt dom bent, blijkt dat het hebben van een taal die vereenvoudigde aannames maakt, wat betekent dat je niet ‘ Het is nog steeds nuttig om over bepaalde dingen na te denken om ze te laten werken.CPython is geweldig voor bepaalde dingen, inclusief eenvoudige multithread-applicaties (waarbij het programma IO-gebonden is, wat veel wel is, en daarom doet de GIL er niet toe), omdat de ontwerpbeslissingen die de GIL de beste oplossing maakt het programmeren van die applicaties ook gemakkelijker, met name het feit dat het atomaire bewerkingen op verzamelingen ondersteunt.
  • @Jules Ja, het ‘ is erg handig totdat je die mogelijkheden nodig hebt. cpython ‘ s ” voorkeur ” oplossing van ” schrijf het gewoon in een andere taal zoals c ++ ” betekent dat je elk afzonderlijk python-voordeel verliest. Als je ‘ de helft van je code aan het schrijven bent in c ++, waarom zou je dan beginnen met Python? Zeker, voor kleine API / glue-projecten is het ‘ snel en gemakkelijk, en voor ETL is het ‘ ongeëvenaard, maar het ‘ is niet geschikt voor iets dat zwaar moet tillen. Hetzelfde als Java gebruiken om met hardware te praten … Het ‘ is bijna komisch de hoepels waar je doorheen moet springen.
  • @Basic One van Python ‘ s en dus tot op zekere hoogte CPython ‘ s kernfilosofieën is om de technologie ” vriendelijk en gemakkelijk te gebruiken “. Parallel programmeren zonder globale vergrendeling is dat niet . Gezien het feit dat er veel implementaties zijn zonder GIL, is het zinvol om ten minste één implementatie te bieden die dit wel heeft.
  • U zegt ” het is logisch om op zijn minst één implementatie die het heeft. ” vind het leuk ‘ is de voor de hand liggende conclusie, maar geen andere taal Ik ‘ Ik ben me ervan bewust dat zijn ontwikkelaars op deze manier hinder ondervinden, dus het kan ‘ niet dat voor de hand liggend zijn.

Answer

Wat is het doel van een GIL?

De CAPI-documentatie heeft het volgende te zeggen over het onderwerp:

De Python-interpreter is niet volledig thread-safe . Om Python-programmas met meerdere threads te ondersteunen, is er een globale vergrendeling, de zogenaamde global interpreter lock of GIL, die moet worden vastgehouden door de huidige thread voordat deze veilig toegang kan krijgen tot Python-objecten. Zonder de vergrendeling zouden zelfs de eenvoudigste bewerkingen problemen kunnen veroorzaken in een programma met meerdere threads: als bijvoorbeeld twee threads tegelijkertijd de referentietelling van hetzelfde object verhogen, zou de referentietelling uiteindelijk slechts één keer in plaats van twee keer kunnen worden verhoogd.

Met andere woorden, de GIL voorkomt corruptie van de staat. Python-programmas mogen nooit een segmentatiefout produceren, omdat alleen geheugenveilige bewerkingen zijn toegestaan. De GIL breidt deze garantie uit naar multi-threaded programmas.

Wat zijn de alternatieven?

Als het doel van de GIL is om de staat te beschermen tegen corruptie, dan is een voor de hand liggend alternatief een veel fijnere korrel; misschien op een per objectniveau. Het probleem hiermee is dat, hoewel is aangetoond dat het de prestaties van multi-threaded programmas verbetert, het meer overhead heeft en dat single-threaded programmas als gevolg daarvan lijden.

Opmerkingen

  • Het zou geweldig zijn om een gebruiker een programma te laten draaien met een interpreter-optie die de gil vervangt door fijnmazige vergrendeling, en op de een of andere manier te weten – op een alleen-lezen manier – of het huidige proces is gestart met of zonder gil.
  • Ondanks GIL slaagde ik erin om een segmentatiefout te produceren in een multithreaded programma vanwege onzorgvuldig gebruik van module pyodbc. ” mag dus nooit een segmentatiefout produceren ” is een misvatting.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *