Python’da threading ve multiprocessing, aynı anda birden fazla görevi gerçekleştirmek için kullanılan paralel programlama teknikleridir. Bu teknikler, programların performansını artırmak ve zaman alıcı işlemleri daha verimli bir şekilde yürütmek için kullanılır.
1. Threading
Threading, bir programın aynı anda birden fazla iş parçacığı (thread) kullanarak çalışmasını sağlar. İş parçacıkları, aynı süreç içinde çalışan hafif alt süreçlerdir ve belleği paylaşarak çalışırlar. Threading, özellikle I/O-bound işlemler için kullanışlıdır (örneğin, dosya okuma/yazma, ağ işlemleri).
a. Basit Bir Threading Örneği
Örnek:
import threading
import time
def bekle(sure, isim):
print(f"{isim} beklemeye başlıyor.")
time.sleep(sure)
print(f"{isim} beklemeyi bitirdi.")
# İki iş parçacığı oluşturma
t1 = threading.Thread(target=bekle, args=(2, "Thread 1"))
t2 = threading.Thread(target=bekle, args=(4, "Thread 2"))
# İş parçacıklarını başlatma
t1.start()
t2.start()
# İş parçacıklarının bitmesini bekleme
t1.join()
t2.join()
print("Ana program sona erdi.")
Bu örnekte:
- İki ayrı iş parçacığı (
t1
vet2
) oluşturulur ve aynı anda çalıştırılır. t1
2 saniye,t2
ise 4 saniye boyunca bekler.join()
metodları, ana programın iş parçacıkları tamamlanana kadar beklemesini sağlar.
Çıktı:
Thread 1 beklemeye başlıyor.
Thread 2 beklemeye başlıyor.
Thread 1 beklemeyi bitirdi.
Thread 2 beklemeyi bitirdi.
Ana program sona erdi.
b. Threading ile Paylaşılan Veriler
Threading kullanırken, iş parçacıkları arasında veri paylaşımı yapılabilir. Ancak, bu durum veri yarışmaları (race condition) ve senkronizasyon sorunlarına yol açabilir.
Örnek:
import threading
sayac = 0
def arttir():
global sayac
for _ in range(100000):
sayac += 1
# İki iş parçacığı oluşturma
t1 = threading.Thread(target=arttir)
t2 = threading.Thread(target=arttir)
# İş parçacıklarını başlatma
t1.start()
t2.start()
# İş parçacıklarının bitmesini bekleme
t1.join()
t2.join()
print("Sayac:", sayac)
Bu örnekte:
- İki iş parçacığı
sayac
değişkenini aynı anda artırır. - Veri yarışması nedeniyle sonuç beklenenden düşük olabilir.
c. Threading ile Senkronizasyon (Lock Kullanımı)
Veri yarışmalarını önlemek için threading.Lock()
kullanılarak senkronizasyon sağlanabilir.
Örnek:
import threading
sayac = 0
lock = threading.Lock()
def arttir():
global sayac
for _ in range(100000):
with lock:
sayac += 1
# İki iş parçacığı oluşturma
t1 = threading.Thread(target=arttir)
t2 = threading.Thread(target=arttir)
# İş parçacıklarını başlatma
t1.start()
t2.start()
# İş parçacıklarının bitmesini bekleme
t1.join()
t2.join()
print("Sayac:", sayac)
Bu örnekte:
lock
kullanılaraksayac
değişkenine aynı anda sadece bir iş parçacığının erişmesine izin verilir.- Bu şekilde veri yarışması önlenir.
2. Multiprocessing
Multiprocessing, aynı anda birden fazla işlem (process) kullanarak çalışmayı sağlar. Her işlem kendi belleğine sahiptir ve diğer işlemlerden izole edilmiştir. Multiprocessing, özellikle CPU-bound işlemler için kullanışlıdır (örneğin, yoğun hesaplama işlemleri).
a. Basit Bir Multiprocessing Örneği
Örnek:
import multiprocessing
import time
def bekle(sure, isim):
print(f"{isim} beklemeye başlıyor.")
time.sleep(sure)
print(f"{isim} beklemeyi bitirdi.")
# İki işlem oluşturma
p1 = multiprocessing.Process(target=bekle, args=(2, "Process 1"))
p2 = multiprocessing.Process(target=bekle, args=(4, "Process 2"))
# İşlemleri başlatma
p1.start()
p2.start()
# İşlemlerin bitmesini bekleme
p1.join()
p2.join()
print("Ana program sona erdi.")
Bu örnekte:
- İki ayrı işlem (
p1
vep2
) oluşturulur ve aynı anda çalıştırılır. p1
2 saniye,p2
ise 4 saniye boyunca bekler.
Çıktı:
Process 1 beklemeye başlıyor.
Process 2 beklemeye başlıyor.
Process 1 beklemeyi bitirdi.
Process 2 beklemeyi bitirdi.
Ana program sona erdi.
b. Multiprocessing ile Paylaşılan Veriler
İşlemler birbirinden bağımsız belleğe sahip olduklarından, veri paylaşımı yapmak için multiprocessing.Queue
, multiprocessing.Pipe
veya multiprocessing.Manager
kullanılabilir.
Örnek:
import multiprocessing
def kare_al(sayi, queue):
queue.put(sayi * sayi)
queue = multiprocessing.Queue()
# İki işlem oluşturma
p1 = multiprocessing.Process(target=kare_al, args=(2, queue))
p2 = multiprocessing.Process(target=kare_al, args=(3, queue))
# İşlemleri başlatma
p1.start()
p2.start()
# İşlemlerin bitmesini bekleme
p1.join()
p2.join()
# Sonuçları alma
while not queue.empty():
print(queue.get())
Bu örnekte:
multiprocessing.Queue
kullanılarak işlemler arasında veri paylaşımı yapılır.- Her işlem,
queue
nesnesine sonuçlarını ekler.
c. Multiprocessing ile Havuz (Pool) Kullanımı
Multiprocessing havuzu, bir grup iş parçacığını veya işlemi verimli bir şekilde yönetir ve aynı anda birden fazla görevi yürütür.
Örnek:
import multiprocessing
def kare_al(sayi):
return sayi * sayi
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=4)
sonuc = pool.map(kare_al, [1, 2, 3, 4, 5])
print(sonuc)
Bu örnekte:
multiprocessing.Pool
kullanılarak aynı anda birden fazla işlem yürütülür.pool.map
fonksiyonu, listedeki her sayı içinkare_al
fonksiyonunu paralel olarak çalıştırır.
Çıktı:
[1, 4, 9, 16, 25]
3. Threading ve Multiprocessing Arasındaki Farklar
- Threading: Aynı işlem içinde hafif alt süreçlerdir. İş parçacıkları bellek paylaşır ve iletişimleri kolaydır. Ancak, GIL (Global Interpreter Lock) nedeniyle CPU-bound işlemler için sınırlı verim sunar.
- Multiprocessing: Bağımsız işlemler olarak çalışır ve her işlem kendi belleğini kullanır. Bu, CPU-bound işlemler için daha verimlidir, ancak iletişim için ekstra araçlar gerektirir (örneğin, queue, pipe).
4. GIL (Global Interpreter Lock)
Python’da GIL (Global Interpreter Lock), aynı anda sadece bir iş parçacığının Python bayt kodunu yürütmesine izin veren bir mekanizmadır. Bu, threading kullanımında performans sınırlamalarına yol açabilir, özellikle CPU-bound işlemler için. Multiprocessing, GIL’i atlayarak bu sınırlamaları ortadan kaldırır.
Threading ve multiprocessing, Python‘da paralel programlama için iki güçlü tekniktir. Threading, I/O-bound işlemler için uygunken, multiprocessing, CPU-bound işlemler için daha verimlidir. GIL nedeniyle, threading CPU-bound işlemler için sınırlı performans sunabilirken, multiprocessing GIL’in sınırlamalarını aşarak daha iyi performans sağlar. Her iki teknik de paralel ve eşzamanlı programlama için farklı senaryolarda kullanılabilir ve verimlilik sağlar.
Bir yanıt yazın