Middle
Ի՞նչ է GIL (Global Interpreter Lock)-ը Python-ում։
sobes.tech AI
Պատասխան AI-ից
GIL (Աշխարհագրական Ինտերպրետատորի Լոկ) — դա մեխանիզմ է CPython ինտերպրետատորում, որը թույլ է տալիս կատարել միայն մեկ թել (thread) մեկ ժամանակում: Թեև շատականյա պրոցեսորների վրա, GIL-ը չի տալիս թելերին իրականում միաժամանակյա Python կոդի գործարկում:
GIL-ի գոյության պատճառները:
- Հիշողության կառավարման պարզեցում: GIL-ը հեշտացնում է թելային անվտանգ հիշողության կառավարման և աղբի հավաքման (reference counting) իրականացումը: GIL-ի բացակայության դեպքում անհրաժեշտ կլինեին ավելի բարդ և ռեսուրսներ պահանջող սեղմման մեխանիզմներ՝ ընդհանուր տվյալների կառուցվածքները պաշտպանելու համար:
- Կայունություն C գրադարանների հետ: GIL-ը հեշտացնում է ինտեգրացիան C գրադարանների հետ, որոնք կարող են չլինել թելային անվտանգ:
GIL-ի ազդեցությունը:
- CPU-կապված առաջադրանքների պառլելիզմի սահմանափակում: CPU-կապված առաջադրանքների դեպքում, GIL-ը դառնում է խոչընդոտ, քանի որ նույնիսկ շատականյա համակարգերում, գործարկումը չի կատարվում միաժամանակ տարբեր միջուկների վրա: Թելերը պետք է սպասեն, մինչև GIL-ը ազատվի:
- Փոքր ազդեցություն I/O-կապված առաջադրանքների վրա: I/O-կապված առաջադրանքների դեպքում, GIL-ը քիչ է ազդում, քանի որ այն ազատվում է sleep ժամանակ:
GIL-ից խուսափելու միջոցները:
- Բազմամշակութային (Multiprocessing): Փոխարենը թելերի, օգտագործվում են անկախ պրոցեսներ: Յուրաքանչյուր պրոցես ունի իր Python ինտերպրետատորի օրինակ և, հետևաբար, իր GIL-ը: Պրոցեսները կարող են գործարկել միաժամանակ տարբեր միջուկների վրա:
- Ասինխրոն ծրագրավորում (asyncio): Օգտագործում է ասինխրոն I/O մոդել մեկ թելում: Փոխարեն շատ թելեր ստեղծելու, ասինխրոն կոդը փոխում է առաջադրանքների միջև I/O սպասման ժամանակ:
- C/C++ գրադարաններ: Կոդի մասերը, որոնք գրված են C կամ C++, կարող են կատարել գործողություններ առանց GIL պահելու, ազատելով այն այդ գործողությունների ժամանակ:
# GIL-ի ազդեցության օրինակ CPU-կապված առաջադրանքի վրա
import threading
import time
def cpu_bound_task():
count = 0
for i in range(10**7):
count += 1
# Երկու թել ստեղծում CPU-կապված առաջադրանքի համար
t1 = threading.Thread(target=cpu_bound_task)
t2 = threading.Thread(target=cpu_bound_task)
սկիզբ = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
ավարտ = time.time()
print(f"Անցած ժամանակ թելերով (CPU-կապված): {ավարտ - սկիզբ:.2f} վայրկյան") # Ժամանակը մոտավորապես կրկնակի կլինի մեկ առաջադրանքի ժամանակից, GIL-ի պատճառով
# I/O-կապված առաջադրանքի օրինակ, որտեղ GIL-ը քիչ է նկատելի
import threading
import time
def io_bound_task():
time.sleep(1) # I/O սպասման իմիտացիա
# Երկու թել ստեղծում I/O-կապված առաջադրանքի համար
t1 = threading.Thread(target=io_bound_task)
t2 = threading.Thread(target=io_bound_task)
սկիզբ = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
ավարտ = time.time()
print(f"Անցած ժամանակ թելերով (I/O-bound): {ավարտ - սկիզբ:.2f} վայրկյան") # Ժամանակը մոտ 1 վայրկյան կլինի, քանի որ թելերը ազատում են GIL-ը sleep ժամանակ