Ši pamoka bus skirta vienai iš svarbių Python temų – GIL. Taip pat apžvelgsime, kaip GIL veikia Python programų našumą diegiant kodą. Prieš pasinerdami į šią temą, susipažinkime su pagrindine GIL idėja.
GIL arba Global Interpreter Lock
Python Global Interpreter Lock arba GIL yra svarbi daugiasriegio programavimo dalis. Tai yra proceso užrakto tipas, naudojamas dirbant su keliais procesais. Tai leidžia valdyti tik vieną giją. Paprastai „Python“ vienam procesui vykdyti naudoja vieną giją. Naudodami GIL gauname tą patį vienos gijos ir kelių sriegių procesų našumo rezultatą. Tai riboja kelių gijų kūrimą Python, nes apsaugo nuo gijų ir veikia kaip viena gija.
Pastaba – „Python“ nepalaiko kelių gijų, nes gijų paketai negalėjo leisti mums naudoti kelių procesoriaus branduolių.
Kodėl Python Developers naudoja GIL?
Python suteikia unikalią nuorodų skaitiklio funkciją, kuri naudojama atminties valdymui. Nuorodų skaitiklis skaičiuoja bendrą Python viduje padarytų nuorodų skaičių, kad duomenų objektui būtų priskirta reikšmė. Kai atskaitos skaičiai pasiekia nulį, objekto priskirta atmintis išlaisvinama. Pažiūrėkime žemiau pateiktą pavyzdį.
Pavyzdys -
import sys a = [] b = a sys.getrefcount(a)
Pagrindinis susirūpinimas dėl nuorodų skaičiaus kintamojo yra tai, kad jis gali būti paveiktas, kai dvi ar trys gijos vienu metu bando padidinti arba sumažinti jo vertę. Tai žinoma kaip lenktynių būklė. Jei ši sąlyga įvyksta, dėl to gali nutekėti atmintis, kuri niekada neišleidžiama. Jis gali sugesti arba sugesti Python programoje.
GIL padeda mums pašalinti tokią situaciją, naudojant užraktus visose gijose bendrinamose duomenų struktūrose, kad jos nebūtų keičiamos nenuosekliai. „Python“ yra paprastas būdas įdiegti GIL, nes jis susijęs su saugiu atminties valdymu. GIL reikalauja siūlyti vieną užraktą gijai apdoroti Python. Tai padidina vienos gijos programos našumą, nes reikia tvarkyti tik vieną užraktą. Tai taip pat padeda sukurti bet kokią su CPU susijusią programą ir apsaugo nuo aklavietės.
Poveikis kelių gijų Python programoms
Yra skirtumas tarp procesoriaus našumo ribų ir įvesties / išvesties, skirtos tipinei Python programai ar bet kuriai kompiuterio programai. Su procesoriaus susietos programos paprastai stumia CPU iki jo ribų. Šios programos paprastai naudojamos matematiniams skaičiavimams, tokiems kaip matricos daugyba, skrudinimas, vaizdo apdorojimas ir kt.
eilutę prie itn
Įvesties/išvesties programos yra tos programos, kurios praleidžia laiką, kad gautų įvestį/išvestį, kurią gali sugeneruoti vartotojas, failas, duomenų bazė, tinklas ir tt Tokios programos turi palaukti nemažai laiko, kol šaltinis pateiks įvestį. Kita vertus, šaltinis taip pat turi savo apdorojimo laiką. Pavyzdžiui – vartotojas galvoja, ką įvesti kaip įvestį.
Supraskime šį pavyzdį.
int į eilutę java
Pavyzdys -
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)
Išvestis:
Time taken in seconds - 7.422671556472778
Dabar modifikuojame aukščiau pateiktą kodą paleisdami dvi temas.
Pavyzdys – 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)
Išvestis:
Time taken in seconds - 6.90830135345459
Kaip matome, abu kodai užbaigti užtruko tiek pat laiko. GIL neleido su CPU susietoms gijomis vykdyti lygiagrečiai antrajame kode.
Kodėl GIL dar nepašalintas?
Daugelis programuotojų dėl to skundžiasi, tačiau Python negali padaryti tokių reikšmingų pakeitimų kaip GIL pašalinimas. Kita priežastis yra ta, kad GIL iki šiol nėra patobulinta. Jei tai pasikeis Python 3, tai sukels rimtų problemų. Užuot pašalinus GIL, GIL koncepcija gali patobulinti. Pasak Guido van Rossom,
„Aš sveikinu Py3k pataisų rinkinį tik tuo atveju, jei vienos gijos programos (ir kelių gijų, bet su įvesties / išvesties susietos programos) našumas nesumažės“.
trinarinis operatorius java
Taip pat yra daug metodų, kurie išsprendžia tą pačią problemą, kurią išsprendė GIL, tačiau juos sunku įgyvendinti.
Kaip elgtis su Python GIL
Daugiafunkcinis apdorojimas yra tinkamiausias būdas apsaugoti programą nuo GIL. „Python“ kiekvienam procesui siūlo įvairius interpretatorius, todėl pagal šį scenarijų kiekvienam kelių apdorojimo procesui suteikiama viena gija. Supraskime šį pavyzdį.
Pavyzdys -
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)
Išvestis:
Time taken in seconds - 3.3707828521728516
Gali atrodyti, kad našumas padidės, tačiau procesų valdymas turi savo pridėtines išlaidas, o keli procesai yra sunkesni nei kelios gijos.
Išvada
Šioje pamokoje aptarėme GIL ir kaip galime juo naudotis. Tai suteikia galimybę valdyti vieną giją, kurią reikia vykdyti vienu metu. Šioje pamokoje taip pat buvo aptarta, kodėl GIL yra svarbi Python programuotojams.