Tento tutoriál bude zaměřen na jedno z důležitých témat Pythonu, GIL. Budeme se také zabývat tím, jak GIL ovlivňuje výkon programů Python s implementací kódu. Než se vrhneme na toto téma, udělejme si základní představu o GIL.
GIL nebo Global Interpreter Lock
Python Global Interpreter Lock neboli GIL je důležitou součástí multithreadingového programování. Jedná se o typ procesního zámku, který se používá při práci s více procesy. Dává kontrolu pouze jednomu vláknu. Obecně Python používá jedno vlákno ke spuštění jednoho procesu. Získáme stejný výsledek výkonu jednovláknových a vícevláknových procesů pomocí GIL. Omezuje dosažení multithreadingu v Pythonu, protože zabraňuje vláknům a funguje jako jediné vlákno.
Poznámka - Python nepodporuje multithreading, protože balíčky s vlákny nám neumožňují používat více jader CPU.
Proč vývojáři Pythonu používají GIL?
Python poskytuje jedinečnou funkci počítadla odkazů, která se používá pro správu paměti. Čítač odkazů počítá celkový počet odkazů provedených interně v Pythonu za účelem přiřazení hodnoty datovému objektu. Když počty referencí dosáhnou nuly, přiřazená paměť objektu se uvolní. Podívejme se na níže uvedený příklad.
Příklad -
c booleovský
import sys a = [] b = a sys.getrefcount(a)
Hlavním problémem proměnné počtu odkazů je to, že může být ovlivněna, když se dvě nebo tři vlákna pokoušejí zvýšit nebo snížit její hodnotu současně. To je známé jako rasová podmínka. Pokud tato podmínka nastane, může to být způsobeno únikem paměti, která není nikdy uvolněna. Může dojít k selhání nebo chybám v programu Python.
GIL nám pomáhá odstranit takovou situaci pomocí zámků všech sdílených datových struktur napříč vlákny, aby se neměnily nekonzistentně. Python poskytuje snadný způsob, jak implementovat GIL, protože se zabývá správou paměti zabezpečenou proti vláknům. GIL vyžaduje nabízení jediného zámku pro vlákno pro zpracování v Pythonu. Zvyšuje výkon jednovláknového programu, protože vyžaduje obsluhu pouze jednoho zámku. Pomáhá také vytvořit jakýkoli program vázaný na CPU a zabraňuje stavu uváznutí.
Vliv na vícevláknové programy Pythonu
Existuje rozdíl mezi limity CPU v jejich výkonu a limity I/O pro typický program Python nebo jakýkoli počítačový program. Programy vázané na CPU obecně tlačí CPU na jeho limity. Tyto programy se obecně používají pro matematické výpočty, jako je násobení matic, searing, zpracování obrazu atd.
Programy vázané na vstup/výstup jsou programy, které tráví čas získáním vstupu/výstupu, který může generovat uživatel, soubor, databáze, síť atd. Takové programy musí nějakou značnou dobu čekat, než zdroj poskytne vstup. Na druhou stranu má zdroj také svůj vlastní čas zpracování. Například – uživatel přemýšlí, co zadat jako vstup.
Pojďme pochopit následující příklad.
int do řetězce java
Příklad -
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)
Výstup:
Time taken in seconds - 7.422671556472778
Nyní upravíme výše uvedený kód spuštěním dvou vláken.
Příklad – 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)
Výstup:
Time taken in seconds - 6.90830135345459
Jak vidíme, dokončení obou kódů trvalo stejnou dobu. GIL zabránil paralelnímu spouštění vláken vázaných na CPU ve druhém kódu.
Proč nebyl GIL dosud odstraněn?
Mnoho programátorů si na to stěžuje, ale Python nemůže přinést změny tak významné jako odstranění GIL. Dalším důvodem je, že GIL není nyní vylepšen. Pokud se v Pythonu 3 změní, způsobí to vážné problémy. Místo odstranění GIL může koncept GIL zlepšit. Podle Guida van Rossoma -
'Uvítal bych sadu záplat do Py3k pouze v případě, že se výkon pro jednovláknový program (a pro vícevláknový, ale I/O-vázaný program) nesníží.
jakou mám velikost monitoru
Existuje také mnoho dostupných metod, které řeší stejný problém řešený GIL, ale je těžké je implementovat.
Jak se vypořádat s GIL Pythonu
Použití multiprocessingu je nejvhodnější způsob, jak zabránit programu GIL. Python nabízí různé interprety pro každý proces ke spuštění, takže v tomto scénáři je každému procesu v multiprocesingu poskytnuto jediné vlákno. Pojďme pochopit následující příklad.
Příklad -
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)
Výstup:
Time taken in seconds - 3.3707828521728516
Může se zdát, že se zvýšil slušný výkon, ale řízení procesů má svou vlastní režii a více procesů je těžších než více vláken.
Závěr
V tomto tutoriálu jsme probrali GIL a jak jej můžeme používat. Dává kontrolu jednomu vláknu, které se má v daném okamžiku spustit. Tento tutoriál také popsal, proč je GIL důležitý pro programátory Pythonu.