Middle
Python'da GIL (Global Interpreter Lock) nedir?
sobes.tech yapay zeka
AI'dan gelen yanıt
GIL (Global Interpreter Lock), CPython yorumlayıcısında, yalnızca bir akışın (thread) aynı anda çalışmasına izin veren bir mekanizmadır. Çok çekirdekli işlemcilerde bile, GIL Python kodunun gerçek anlamda paralel çalışmasını engeller.
GIL'in varoluş nedenleri:
- Bellek yönetiminin basitleştirilmesi: GIL, akışlar için güvenli bellek yönetimi ve çöp toplama (referans sayımı) uygulamasını basitleştirir. GIL olmadan, ortak veri yapılarının korunması için daha karmaşık ve kaynak maliyetli kilit mekanizmaları gerekirdi.
- C kütüphaneleriyle uyumluluk: GIL, mevcut C kütüphaneleriyle entegrasyonu kolaylaştırır; bu kütüphaneler akış güvenli olmayabilir.
GIL'in etkileri:
- CPU-bound görevlerde paralellik sınırlaması: CPU yoğun görevlerde, GIL darboğaz haline gelir çünkü çok çekirdekli sistemlerde bile, işler çekirdekler arasında paralel çalışmaz. Akışlar, GIL serbest bırakılana kadar bekler.
- I/O-bound görevlerde daha az etkili: Ağ istekleri veya dosya işlemleri gibi I/O yoğun görevlerde, GIL daha az kritiktir. I/O işlemleri sırasında, akış GIL'i serbest bırakır ve diğer akışların çalışmasına izin verir.
GIL'den kaçınma yolları:
- Çok işlemcilik (Multiprocessing): Akışlar yerine, bağımsız süreçler kullanılır. Her süreç kendi Python yorumlayıcısına ve dolayısıyla kendi GIL'ine sahiptir. Süreçler, farklı çekirdeklerde paralel çalışabilir.
- Asenkron programlama (asyncio): Tek bir akışta asenkron giriş/çıkış modeli kullanır. Çok sayıda akış yerine, I/O beklerken görevler arasında geçiş yapılır. GIL, CPU ile ilgili görevlerin paralel yürütülmesine engel olmadığı için, bu modelde etkisi azdır.
- C/C++ kütüphaneleri: C veya C++ ile yazılmış kod parçaları, GIL'i tutmadan işlemleri gerçekleştirebilir; bu, bu işlemler sırasında GIL'in serbest bırakılmasını sağlar. NumPy ve SciPy gibi popüler kütüphaneler, yüksek performanslı hesaplamalar için bunu kullanır.
# CPU-bound görevin GIL etkisini gösteren örnek
import threading
import time
def cpu_bound_task():
count = 0
for i in range(10**7):
count += 1
# CPU-bound görevi çalıştırmak için iki akış oluşturma
t1 = threading.Thread(target=cpu_bound_task)
t2 = threading.Thread(target=cpu_bound_task)
start_time = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
end_time = time.time()
print(f"GIL nedeniyle akışlarla (CPU-bound) çalışma süresi: {end_time - start_time:.2f} saniye") # Süre, yaklaşık olarak tek bir görevin çalıştırılmasından iki kat daha uzun olacaktır.
# I/O-bound görev örneği, GIL'in daha az belirgin olduğu durum
import threading
import time
def io_bound_task():
time.sleep(1) # I/O bekleme simülasyonu
# I/O-bound görev için iki akış oluşturma
t1 = threading.Thread(target=io_bound_task)
t2 = threading.Thread(target=io_bound_task)
start_time = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
end_time = time.time()
print(f"I/O-bound ile akışlar (GIL daha az etkili): {end_time - start_time:.2f} saniye") # Süre yaklaşık 1 saniye olacaktır, çünkü akışlar sleep sırasında GIL'i serbest bırakır.