Denne tutorial vil være fokuseret på et af vigtige Pythons emner, GIL. Vi vil også dække, hvordan GIL påvirker Python-programmernes ydeevne med kodeimplementeringen. Før vi dykker ned i dette emne, lad os få en grundlæggende idé om GIL.
GIL eller Global Interpreter Lock
Python Global Interpreter Lock eller GIL er en vigtig del af multithreading-programmering. Det er en type proceslås, der bruges, når man arbejder med flere processer. Det giver kun kontrollen til én tråd. Generelt bruger Python en enkelt tråd til at køre en enkelt proces. Vi får det samme præstationsresultat af enkelt- og flertrådede processer ved hjælp af GIL. Det begrænser opnåelse af multithreading i Python, fordi det forhindrer trådene og fungerer som en enkelt tråd.
Bemærk - Python understøtter ikke multithreading, fordi threading-pakker ikke kunne lade os bruge de flere CPU-kerner.
Hvorfor Python-udviklere bruger GIL?
Python giver den unikke referencetællerfunktion, som bruges til hukommelsesstyring. Referencetælleren tæller det samlede antal referencer foretaget internt i Python for at tildele en værdi til et dataobjekt. Når referencetællingerne når nul, frigives den tildelte hukommelse for objektet. Lad os se nedenstående eksempel.
Eksempel -
import sys a = [] b = a sys.getrefcount(a)
Den største bekymring med referencetællingsvariablen er, at den kan blive påvirket, når to eller tre tråde forsøger at øge eller mindske dens værdi samtidigt. Det er kendt som race tilstand. Hvis denne tilstand opstår, kan det skyldes lækket hukommelse, der aldrig frigives. Det kan gå ned eller fejl i Python-programmet.
GIL hjælper os med at fjerne en sådan situation ved at bruge låsene til alle delte datastrukturer på tværs af tråde, så de ikke ændres inkonsekvent. Python giver en nem måde at implementere GIL på, da den beskæftiger sig med trådsikker hukommelseshåndtering. GIL kræver at tilbyde en enkelt lås til en tråd til behandling i Python. Det øger ydelsen af et enkelt-trådet program, da kun én lås skal håndteres. Det hjælper også med at lave et hvilket som helst CPU-bundet program og forhindrer deadlocks-tilstanden.
avl trærotation
Indvirkningen på flertrådede Python-programmer
Der er en forskel mellem CPU-grænser i deres ydeevne og I/O bundet for et typisk Python-program eller et hvilket som helst computerprogram. CPU-bundne programmer presses generelt CPU'en til dets grænser. Disse programmer bruges generelt til matematisk beregning såsom matrixmultiplikationer, searing, billedbehandling osv.
I/O-bundne programmer er de programmer, der bruger tid på at få input/output, der kan genereres af brugeren, filen, databasen, netværket osv. Sådanne programmer skal vente i et betydeligt tidsrum, indtil kilden leverer inputtet. På den anden side har kilden også sin egen behandlingstid. For eksempel - en bruger tænker på, hvad der skal indtastes som input.
Lad os forstå følgende eksempel.
Eksempel -
import time from threading import Thread COUNT = 100000000 def countdown(num): while num>0: num -= 1 start_time = time.time() countdown(COUNT) end_time = time.time() print('Time taken in seconds -', end_time - start_time)
Produktion:
Time taken in seconds - 7.422671556472778
Nu ændrer vi ovenstående kode ved at køre de to tråde.
Eksempel - 2:
import time from threading import Thread COUNT = 100000000 def countdown(num): while num>0: num -= 1 thread1 = Thread(target=countdown, args=(COUNT//2,)) thread2 = Thread(target=countdown, args=(COUNT//2,)) start_time = time.time() thread1.start() thread2.start() thread1.join() thread2.join() end_time = time.time() print('Time taken in seconds -', end_time - start_time)
Produktion:
Time taken in seconds - 6.90830135345459
Som vi kan se, at begge koder tog samme tid at afslutte. GIL forhindrede de CPU-bundne tråde i at køre parallelt i den anden kode.
Hvorfor er GIL ikke blevet fjernet endnu?
Mange programmører har en klage over dette, men Python kan ikke bringe ændringerne så væsentlige som fjernelsen af GIL. En anden grund er, at GIL ikke er forbedret lige nu. Hvis det ændres i Python 3, vil det skabe nogle alvorlige problemer. I stedet for at fjerne GIL, kan GIL-konceptet forbedres. Ifølge Guido van Rossom -
'Jeg vil kun byde velkommen til et sæt patches i Py3k, hvis ydeevnen for et enkelt-trådet program (og for et flertrådet, men I/O-bundet program) ikke falder'.
Der er også mange tilgængelige metoder, der løser det samme problem, løst af GIL, men der er svære at implementere.
Sådan håndteres Pythons GIL
Brug af multiprocessing er den mest egnede måde at forhindre programmet i at få GIL. Python tilbyder forskellige fortolkere til hver proces at køre, så i det scenarie leveres den enkelte tråd til hver proces i multiprocessing. Lad os forstå følgende eksempel.
Eksempel -
from multiprocessing import Pool import time COUNT = 50000000 def countdown(num): while num>0: num -= 1 if __name__ == '__main__': pool = Pool(processes=2) start_time = time.time() r1 = pool.apply_async(countdown, [COUNT//2]) r2 = pool.apply_async(countdown, [COUNT//2]) pool.close() pool.join() end_time = time.time() print('Time taken in seconds -', end_time - start_time)
Produktion:
Time taken in seconds - 3.3707828521728516
Det kan synes, at en anstændig ydeevne er øget, men processtyring har sine egne omkostninger, og flere processer er tungere end flere tråde.
Konklusion
I denne tutorial har vi diskuteret GIL, og hvordan vi kan bruge den. Det giver kontrollen til en enkelt tråd til at udføre på et tidspunkt. Denne tutorial dækkede også, hvorfor GIL er vigtig for Python-programmører.