Thread tabanlı eşzamanlılık ile async I/O (event loop) arasındaki fark nedir? I/O-bound ve CPU-bound işlerde hangisini seçersiniz?

Cevap

Thread modelinde her istek için bir thread bloklanarak bekler; işletim sistemi thread'ler arasında geçiş yapar. Async I/O modelinde az sayıda thread (çoğu zaman tek) bir event loop çalıştırır; I/O başlatılır, beklenmez, hazır olduğunda kernel bildirir (epoll, kqueue, IOCP) ve ilgili callback/coroutine devam ettirilir.

Karşılaştırma

Thread başına istekAsync / event loop
BellekHer thread için stack (Linux'ta varsayılan 8 MB sanal, gerçek kullanım daha az)Coroutine başına birkaç KB
Context switchKernel seviyesinde, pahalıKullanıcı seviyesinde, ucuz
10.000+ eşzamanlı bağlantıZorlanırRahat ölçeklenir
Kod okunabilirliğiDüz, sıralı kodasync/await ile iyi, ama "function coloring" sorunu
CPU-yoğun işÇok çekirdeği kullanabilir (dile bağlı)Event loop'u bloklar, tüm istekler bekler

I/O-bound ve CPU-bound

  • I/O-bound (HTTP çağrıları, veritabanı, dosya): zamanın çoğu beklemekle geçer. Async I/O veya hafif thread'ler idealdir.
  • CPU-bound (görüntü işleme, şifreleme, büyük hesaplamalar): bekleme yoktur, çekirdek sayısı kadar paralellik gerekir. Async işe yaramaz; process/thread havuzu kullanılır.

Python örneği

import asyncio, time
from concurrent.futures import ProcessPoolExecutor

async def fetch(i):
    await asyncio.sleep(1)          # I/O'yu taklit eder, loop'u bloklamaz
    return i

def heavy(n):
    return sum(x * x for x in range(n))   # CPU-bound

async def main():
    t = time.perf_counter()
    await asyncio.gather(*(fetch(i) for i in range(100)))
    print(f"100 I/O işi: {time.perf_counter() - t:.1f}s")  # ~1.0s

    loop = asyncio.get_running_loop()
    with ProcessPoolExecutor() as pool:   # CPU işini loop dışına taşı
        await asyncio.gather(*(loop.run_in_executor(pool, heavy, 10**6) for _ in range(4)))

if __name__ == "__main__":   # ProcessPoolExecutor için gerekli (spawn/forkserver)
    asyncio.run(main())

CPython'da GIL nedeniyle thread'ler CPU-bound işi paralel çalıştıramaz. Python 3.13'te deneysel olarak gelen free-threaded (GIL'siz) build, 3.14 ile resmi olarak desteklenir hâle geldi ama hâlâ varsayılan değildir; bu yüzden CPU işleri için ProcessPoolExecutor tercih edilir.

Orta yol: hafif thread'ler

Go goroutine'leri ve Java 21 virtual thread'leri, sıralı (bloklayan görünümlü) kod yazmanıza izin verirken arka planda async I/O kullanır. Bu, thread modelinin okunabilirliğini async modelin ölçeklenebilirliğiyle birleştirir.

Sık hata

Async bir handler içinde bloklayan çağrı (time.sleep, senkron DB sürücüsü, ağır JSON parse) yapmak tüm event loop'u durdurur. Node.js'te de aynı sorun geçerlidir.

  1. Concurrency ile parallelism arasındaki fark nedir?Kolayİşletim SistemleriYazılım Müh.
  2. Race condition nedir? Bir örnekle nasıl önleneceğini gösterin.Ortaİşletim SistemleriYazılım Müh.
  3. Context switch nedir? Neden maliyetlidir?Ortaİşletim SistemleriYazılım Müh.
  4. Virtual memory ve paging nasıl çalışır? Page fault nedir?Zorİşletim SistemleriYazılım Müh.
  5. Mutex ile semaphore arasındaki fark nedir?Ortaİşletim SistemleriYazılım Müh.
  6. Deadlock nedir? Oluşması için gereken dört koşul nelerdir ve nasıl önlenir?Zorİşletim SistemleriYazılım Müh.

Bu konuda başka bir soru biliyor musun?

Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.

Soru ekle