Programmering

Multicore Python: Et hårdt, værdigt og tilgængeligt mål

For alle Pythons fantastiske og praktiske funktioner forbliver et mål uden for rækkevidde: Python-apps, der kører på CPython-referencetolken og bruger flere CPU-kerner parallelt.

Dette har længe været en af ​​Pythons største snublesten, især da alle løsningerne er klodsede. Det haster med at finde en langsigtet løsning på problemet vokser, især da kernetællinger på processorer fortsætter med at løbe op (se Intels 24-core behemoth).

En lås for alle

I virkeligheden er det muligt at bruge tråde i Python-applikationer - mange af dem gør det allerede. Hvad er der?ikke muligt er for CPython at køre multitrådede applikationer med hver tråd, der udføres parallelt på en anden kerne. CPythons interne hukommelsesadministration er ikke trådsikker, så tolken kører kun en tråd ad gangen, skifter mellem dem efter behov og kontrollerer adgangen til den globale tilstand.

Denne låsemekanisme, Global Interpreter Lock (GIL), er den største enkeltårsag til, at CPython ikke kan køre tråde parallelt. Der er nogle formildende faktorer; for eksempel er I / O-operationer som disk- eller netværkslæsninger ikke bundet af GIL, så de kan køre frit i deres egne tråde. Men alt, hvad både multithreaded og CPU-bundet er et problem.

For Python-programmører betyder det, at tunge beregningsopgaver, der har fordel af at være spredt ud over flere kerner, ikke kører godt, hvilket forhindrer brugen af ​​et eksternt bibliotek. Bekvemmeligheden ved at arbejde i Python har en stor præstationsomkostning, som bliver sværere at sluge, da hurtigere, lige så bekvemme sprog som Googles Go kommer i forgrunden.

Vælg låsen

Over tid er der opstået en række muligheder, der forbedrer - men ikke eliminerer - grænserne for GIL. En standard taktik er at starte flere forekomster af CPython og dele kontekst og tilstand mellem dem; hver instans kører uafhængigt af den anden i en separat proces. Men som Jeff Knupp forklarer, kan gevinsterne ved at køre parallelt gå tabt af den nødvendige indsats for at dele tilstand, så denne teknik er bedst egnet til langvarige operationer, der samler deres resultater over tid.

C-udvidelser er ikke bundet af GIL, så mange biblioteker til Python, der har brug for hastighed (såsom matematik- og statistikbiblioteket Numpy) kan køre på tværs af flere kerner. Men begrænsningerne i selve CPython forbliver. Hvis den bedste måde at undgå GIL på er at bruge C, vil det køre flere programmører væk fra Python og mod C.

PyPy, Python-versionen, der kompilerer kode via JIT, slipper ikke af med GIL, men kompenserer for det ved blot at lade koden køre hurtigere. På nogle måder er dette ikke en dårlig erstatning: Hvis hastighed er hovedårsagen til, at du har set multithreading, kan PyPy muligvis levere hastigheden uden komplikationerne ved multithreading.

Endelig blev GIL selv bearbejdet noget i Python 3 med en bedre tråd-skiftehåndterer. Men alle dens underliggende antagelser - og begrænsninger - forbliver. Der er stadig en GIL, og den fortsætter stadig proceduren.

Ingen GIL? Intet problem

På trods af alt dette fortsætter søgen efter en GIL-mindre Python, kompatibel med eksisterende applikationer. Andre implementeringer af Python har fjernet GIL helt, men til en pris. Jython kører for eksempel oven på JVM og bruger JVM's objekt-tracking system i stedet for GIL. IronPython tager den samme tilgang via Microsofts CLR. Men begge lider under inkonsekvent præstation, og de kører nogle gange meget langsommere end CPython. De kan heller ikke let interface med ekstern C-kode, så mange eksisterende Python-applikationer fungerer ikke.

PyParallel, et projekt oprettet af Trent Nelson fra Continuum Analytics, er en "eksperimentel, proof-of-concept-gaffel af Python 3 designet til optimalt at udnytte flere CPU-kerner." Det fjerner ikke GIL, men forbedrer dens indvirkning ved at erstatte asynkronisering modul, så apps, der brugerasynkronisering for parallelisme (såsom multitrådet I / O som en webserver) er mest til gavn. Projektet har ligget i dvale i flere måneder, men dets dokumentation siger, at dets udviklere er komfortable med at tage sig tid til at få det rigtigt, så det til sidst kan medtages i CPython: "Der er ikke noget galt med langsom og stabil, så længe du er på vej i den rigtige retning. "

Et langvarigt projekt af PyPys skabere har været en version af Python, der bruger en teknik kaldet "softwaretransaktionshukommelse" (PyPy-STM). Ifølge PyPys skabere er fordelen "du kan udføre mindre justeringer til dine eksisterende, ikke-multitrådede programmer og få dem til at bruge flere kerner."

PyPy-STM lyder som magi, men det har to ulemper. For det første er det et igangværende arbejde, der i øjeblikket kun understøtter Python 2.x, og for det andet tager det stadig et præstationshit for applikationer, der kører på en enkelt kerne. Da en af ​​de betingelser, der er citeret af Python-skaberen Guido van Rossum for ethvert forsøg på at fjerne GIL fra CPython, er, at dens erstatning ikke skal forringe ydeevnen til enkeltkerne, enkelt-gevind applikationer, en løsning som denne lander ikke i CPython i sin nuværende tilstand.

Skynd dig og vent

Larry Hastings, en vigtig Python-udvikler, delte nogle af sine synspunkter på PyCon 2016 om, hvordan GIL kunne fjernes. Hastings dokumenterede sine forsøg på at fjerne GIL og endte dermed med en version af Python, der ikke havde nogen GIL, men løb kvalmende langsomt på grund af konstante cache-savner.

Du kan miste GIL, opsummeret Hastings, men du skal have en eller anden måde at garantere, at kun en tråd ad gangen ændrer globale objekter - for eksempel ved at have en dedikeret tråd i tolken til at håndtere sådanne tilstandsændringer.

Et stykke af langsigtede gode nyheder er, at hvis og når CPython kaster GIL, vil udviklere, der bruger sproget, allerede være klar til at udnytte multithreading. Mange ændringer er nu bagt i Pythons syntaks, som køer og asynkronisering/vente nøgleord til Python 3.5, gør det let at fordele opgaver på tværs af kerner på et højt niveau.

Alligevel garanterer mængden af ​​arbejde, der er nødvendigt for at gøre Python GIL-mindre, men det vises først i en separat implementering som PyPy-STM. De, der ønsker at prøve et GIL-mindre system, kan gøre det gennem en sådan tredjepartsindsats, men den oprindelige CPython forbliver sandsynligvis uberørt i øjeblikket. Her håber ventetiden ikke er meget længere.