12 - Concurrency, Paralellik ve Asenkron Programlama
2025
Bu hafta, programlarımızı daha verimli ve hızlı hale getirebilmek için kullanabileceğimiz üç önemli kavramı ele alacağız: Eş zamanlılık (concurrency), paralellik (parallelism) ve asenkron programlama (asynchronous programming).
Bu kavramlar sayesinde, bir programın aynı anda birden fazla işi gerçekleştirmesi ya da beklemeden diğer işlemlere geçebilmesi mümkün hale gelir. Özellikle çok çekirdekli işlemcilerin yaygınlaştığı günümüzde bu yetenekler büyük önem taşır.
threading
, multiprocessing
ve asyncio
kütüphanelerinin temel kullanımını öğrenmek,Bu konular, özellikle büyük ve kullanıcı etkileşimli yazılımlarda performans artırmak için gereklidir. Ders boyunca, hem teorik bilgileri hem de uygulamalı örnekleri birlikte göreceğiz.
threading
modülü kullanılır.multiprocessing
modülü kullanılır.asyncio
modülü kullanılır.Threading, aynı program içinde birden fazla iş parçacığının (thread) çalışmasını sağlayan bir tekniktir. Her thread, aynı anda farklı bir işlemi gerçekleştirebilir gibi çalışır. Bu, özellikle I/O-bound (yoğun) işlemlerde performans artırabilir.
import threading
def yaz():
for i in range(5):
print("Yazma işlemi")
def oku():
for i in range(5):
print("Okuma işlemi")
thread1 = threading.Thread(target=yaz)
thread2 = threading.Thread(target=oku)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
Açıklama: İki farklı iş parçacığı (thread) aynı anda çalışıyor.
start()
ile başlatılır,join()
ile tamamlanması beklenir.
Thread’ler aynı anda paylaşılan bir veriyi değiştirirse, beklenmedik sonuçlar ortaya çıkabilir. Buna “race condition” denir. Aşağıdaki örnekte, birden fazla thread aynı anda counter
değişkenini artırmakta ve sonuç her zaman doğru çıkmamaktadır.
import threading
class Counter:
def __init__(self):
self.counter = 0
def increment(self):
self.counter += 1
counter = Counter()
def worker():
for _ in range(1000):
counter.increment()
threads = [threading.Thread(target=worker) for _ in range(10)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
print(counter.counter) # Beklenen: 10000, ama her zaman doğru değil!
import threading
class Counter:
def __init__(self):
self.counter = 0
self.lock = threading.Lock()
def increment(self):
with self.lock:
self.counter += 1
...
Açıklama:
with self.lock
ifadesi sayesinde aynı anda sadece bir threadcounter
değerini değiştirebilir.
import threading
sayi = 0
kilit = threading.Lock()
def arttir():
global sayi
for _ in range(100000):
with kilit:
sayi += 1
threadler = []
for _ in range(10):
t = threading.Thread(target=arttir)
threadler.append(t)
t.start()
for t in threadler:
t.join()
print(sayi)
Açıklama:
with kilit:
sayesinde aynı anda sadece bir threadsayi
değişkenini değiştiriyor.
Multiprocessing, her biri kendi belleğine sahip olan farklı işlemler (process) ile çalışarak gerçek paralellik sağlar. Bu yöntem CPU-bound (yoğun) işlemlerde daha verimlidir.
import multiprocessing
def carp(x):
return x * x
if __name__ == '__main__':
with multiprocessing.Pool(processes=4) as pool:
sonuc = pool.map(carp, [1, 2, 3, 4, 5])
print(sonuc)
Açıklama:
map
fonksiyonu listedeki her bir eleman için farklı bir process çalıştırır.
1’den 100’e kadar sayıların karelerini hesaplayan bir program yazın. Her işlem, 10 sayının karelerini hesaplasın.
from multiprocessing import Process
def calculate_squares(start, end):
result = []
for i in range(start, end + 1):
result.append(i * i)
print(f"{start}-{end} arası kareler: {result}")
if __name__ == "__main__":
processes = []
for i in range(1, 101, 10):
p = Process(target=calculate_squares, args=(i, i + 9))
processes.append(p)
p.start()
for p in processes:
p.join()
print("Tüm işlemler bitti!")
Açıklama: Her işlem, 10’ar sayının karelerini hesaplar ve paralel çalışır.
asyncio, asenkron görevlerin aynı anda yürütülmesini sağlayan bir Python kütüphanesidir. await
ifadesiyle belirtilen işlemler beklenirken başka işler yapılabilir, bu da özellikle I/O-bound (yoğun) işlemler için avantaj sağlar.
import asyncio
async def selamla():
print("Merhaba")
await asyncio.sleep(1)
print("Naber?")
async def main():
await asyncio.gather(selamla(), selamla())
asyncio.run(main())
Açıklama: Aynı anda iki selamla fonksiyonu başlatılıyor.
sleep
sırasında diğeri çalışabiliyor.
Hangisi gerçek paralellik sağlar?