---
title: 'Eşzamansız Programlama'
source: 'https://academia.sh/tr/kurslar/python-eszamanlilik/eszamansiz-programlama'
course: 'Eşzamanlılık ve Başarım'
language: tr
updated: '2026-08-17T18:10:24+00:00'
license: 'CC BY-SA 4.0'
---

# Eşzamansız Programlama

Örtüşmenin kaynağı işletim sistemi değil kodun kendisidir: her adımda denetimi bırakan eş yordam 80 teslimle 31 tik ve 49 örtüşen adım verir, yalnız girdi/çıktı adımında bırakan 54 teslimle 36 tik ve 44 örtüşen adım, hiç bırakmayan 0 teslimle 80 tik ve 0 örtüşen adım.

Önceki iki ders örtüşmeyi hep **dışarıdan** aldı. İş parçacığı işletim sisteminden işçi
istedi, süreç ayrı bir yorumlayıcıdan yuva istedi. İkisinde de hangi görevin ne zaman
ilerleyeceğine karar veren şey kodun dışındaydı; program yalnız kaç akış istediğini söyledi.

Üçüncü bir yol var ve bu ders onu ölçer. **Eşzamansız programlamada** örtüşmenin kaynağı ne
işletim sistemidir ne de ikinci bir yorumlayıcı: **kodun kendisidir.** Bir eş yordam
denetimi bırakacağı yeri kendi yazar. Bu dersin sorusu bu yüzden dar ve sayılabilir: bir eş
yordam denetimi ne sıklıkla bırakırsa ne kadar örtüşme çıkar, ve hiç bırakmazsa ne olur?

## Eş Yordam Sürdürülebilir Bir Gövdedir

**Eş yordam (coroutine)**, çağrıldığında gövdesi koşmayan, çağrıya karşılık bir nesne
döndüren ve **sürdürüldükçe** ilerleyen bir işlevdir. `async def` ile tanımlanır. Gövdesindeki
`await`, bir sonucu bekleyen bir işaret değil, **denetimi bırakma noktasıdır**: eş yordam o
noktada durur, kendini çağıran tarafa döner ve başka bir şeyin ilerlemesine izin verir.

Duraklayan gövde bu kursta ilk kez geçmiyor. **Veri Yapıları ve Fonksiyonel Araçlar** kursu
üreteci ölçtü ve gövdenin `yield`'de durup yerel adlarını koruduğunu gösterdi; o ölçüm burada
tekrarlanmaz. Aradaki fark tek cümlede yazılabilir: **üreteç bir değer vermek için durur, eş
yordam denetimi bırakmak için durur** — birinin duruşu akışa bir öğe ekler, öbürünün duruşu
başkasına sıra verir.

**Olay döngüsü (event loop)** bu duruşları yöneten taraftır. Elinde sürdürülmeyi bekleyen eş
yordamlar vardır; birini sürdürür, o bir teslim noktasına gelip döndüğünde sıradakini sürdürür.
Bir eş yordamı döngüye kaydedip bağımsız ilerlemesini istemek, onu bir **görev** yapmaktır.

## Olay Döngüsü Yeni Bir Yuva Getirmez

Modelin diliyle söylenirse: eşzamansız rejim ne işçi sayısını ne yuva sayısını işletim
sisteminden ister. Olay döngüsü tek bir akışta koşar; aynı anda tek bir gövde ilerler ve
yuva birdir.

O zaman örtüşme nereden gelir? Tek bir yerden: bir gövde denetimi bıraktığında öbürünün
ilerleyebilmesinden. Bu kursun ölçüsüyle, **teslim noktası** olmadan örtüşen adım da yoktur.
Buradan doğrudan bir üst sınır çıkıyor ve ölçüm onu sınayacak: **örtüşen adım, teslim
sayısını geçemez.**

Bunun tersi de var ve dersin sonunda ölçülüyor: teslim etmek örtüşme için **gerekli** ama
**yeterli değil**. Bırakılan denetimi alacak, o anda hazır bekleyen ikinci bir görev de olmak
zorunda.

## Ölçüm Kendi Döngüsünü Yazıyor

Ölçümün çizelgeleyicisi burada elle yazılmış bir olay döngüsüdür; eş yordamlar ise gerçektir.
`async def` ile tanımlanmış, gerçek `await` içeren gövdeler, gerçek eş yordam nesneleri
üretiyor ve `send` ile sürdürülüyor. Değiştirilen tek şey **kimin sürdürdüğü**: standart olay
döngüsü yerine sırası yazılı bir döngü. Sebebi ölçümün koşulu — hangi görevin hangi tikte
sürdürüldüğü sabit olmazsa örtüşen adım sayılamaz.

Dersin sonundaki kısa blok gerçek olay döngüsünü çalıştırıyor ve sırayı `await`'in kendisi
sabitliyor.

Ölçümün varsayımları:

- **EM36** — Görev kurgusu önceki derslerin aynısıdır: sekiz görev, görev başına on adım,
  toplam seksen adım, girdi/çıktı ağırlıklı yük.
- **EM37** — Eş yordamlar gerçektir; `async def` ile tanımlanır ve `await` ile durur. Onları
  sürdüren döngü ders içinde yazılmıştır.
- **EM38** — Teslim noktası, eş yordamın olay döngüsüne dönüş sayısıdır; her `await`
  bir teslimdir.
- **EM39** — Üç rejim yalnız teslim noktalarının yerinde ayrılır: her adımda, yalnız
  girdi/çıktı adımında, hiç. Adım dizileri üçünde de aynıdır.
- **EM40** — Olay döngüsü tek akıştır: işlemci yuvası birdir ve değişmez.
- **EM41** — Bir eş yordam denetimi bırakmadan `k` adım atarsa döngü o `k` adım boyunca
  meşguldür; ilk adım sürdürüldüğü tike yazılır, kalan `k-1` adım kimsenin ilerlemediği ayrı
  tiklere.
- **EM42** — Sürdürme sırası görev indisine göredir ve koşum boyunca değişmez.
- **EM43** — Karşılaştırma tabanı önceki derslerin çizelgeleyicisidir: aynı görevler, sekiz
  işçi, tek yuva.
- **EM44** — Gerçek olay döngüsü yalnız **sıralı `await`** ile çalıştırılır; çıktı sırası
  `await`'in kendisiyle sabitlenir, çizelgeleyiciye bırakılmaz.
- **EM45** — `sleep(0)` bu ölçümde bir bekleme değil, bir **teslim** işaretidir; sayılan şey
  süre değil, denetimin kaç kez bırakıldığıdır.
- **EM46** — Süre ölçülmez; sayılan birim adım, tik, örtüşen adım ve teslimdir.
- **EM47** — Ölçüm tek koşumdur ve tohum sabittir.

## Ölçüm

```python
"""Es yordam: denetimi kim, ne siklikla birakiyor."""

import asyncio

TOHUM = 20260817
ISLEMCI, GC = "islemci", "g_c"


def uretec(tohum):
    d = tohum % 2147483646 + 1

    def r(n):
        nonlocal d
        d = (d * 48271) % 2147483647
        return d % n
    return r


def gorevler(sayi=8, adim=10, gc_payi=7, tohum=TOHUM):
    """Her gorev bir adim dizisi; gc_payi/10 orani girdi/cikti adimi."""
    r, liste = uretec(tohum), []
    for i in range(sayi):
        liste.append([GC if r(10) < gc_payi else ISLEMCI for _ in range(adim)])
    return liste


def kosum(gorevler, isci, islemci_yuvasi):
    """Onceki derslerin cizelgeleyicisi; karsilastirma tabani."""
    kalan = [list(g) for g in gorevler]
    tik = ortusen = 0
    while any(kalan):
        etkin = [i for i, g in enumerate(kalan) if g][:isci]
        if not etkin:
            break
        yuva, ilerleyen = islemci_yuvasi, 0
        for i in etkin:
            if kalan[i][0] == ISLEMCI:
                if yuva <= 0:
                    continue
                yuva -= 1
            kalan[i].pop(0)
            ilerleyen += 1
        tik += 1
        ortusen += max(0, ilerleyen - 1)
    return tik, ortusen


class Bekleyis:
    """Es yordamin denetimi olay dongusune biraktigi nokta."""

    def __init__(self, tur):
        self.tur = tur

    def __await__(self):
        return (yield self.tur)


async def her_adimda(adimlar, gunluk):
    """Her adimdan once denetimi birakir: teslim noktasi = adim sayisi."""
    for a in adimlar:
        await Bekleyis(a)
        gunluk.append(a)


async def gc_adiminda(adimlar, gunluk):
    """Yalniz girdi/cikti adiminda birakir; islemci adimlarini pes pese atar."""
    for a in adimlar:
        if a == GC:
            await Bekleyis(a)
        gunluk.append(a)


async def hic(adimlar, gunluk):
    """Denetimi hic birakmaz."""
    for a in adimlar:
        gunluk.append(a)


def dongu(yapici, gorevler, islemci_yuvasi=1):
    """El yazimi belirlenimci olay dongusu. Donen: tik, ortusen, teslim.

    Bir es yordam denetimi birakmadan k adim atarsa dongu o k adim boyunca
    mesguldur: borc olarak k-1 tik daha yazilir ve o tiklerde kimse ilerlemez.
    """
    gunluk = [[] for _ in gorevler]
    coro = [yapici(g, gunluk[i]) for i, g in enumerate(gorevler)]
    istek = [None] * len(coro)
    canli = [True] * len(coro)
    borc = [0] * len(coro)
    teslim = 0

    def surdur(i, pesin=0):
        nonlocal teslim
        onceki = len(gunluk[i])
        try:
            istek[i] = coro[i].send(None)
            teslim += 1
        except StopIteration:
            istek[i] = None
            canli[i] = False
        borc[i] += max(0, len(gunluk[i]) - onceki - pesin)

    for i in range(len(coro)):
        surdur(i)                       # ilk teslim noktasina kadar
    tik = ortusen = 0
    while any(canli) or any(borc):
        mesgul = [i for i in range(len(coro)) if borc[i] > 0]
        if mesgul:
            borc[mesgul[0]] -= 1
            tik += 1
            continue
        yuva, ilerleyen = islemci_yuvasi, 0
        for i in range(len(coro)):
            if not canli[i] or istek[i] is None:
                continue
            if istek[i] == ISLEMCI:
                if yuva <= 0:
                    continue
                yuva -= 1
            surdur(i, 1)
            ilerleyen += 1
        if ilerleyen == 0:
            break
        tik += 1
        ortusen += max(0, ilerleyen - 1)
    return tik, ortusen, teslim


g = gorevler(gc_payi=7)
print("girdi/çıktı ağırlıklı yük, seksen adım, tek yuva")
print(f"{'teslim noktası':<24s} {'teslim':>7s} {'tik':>5s} {'örtüşen':>8s}")
for ad, yapici in (("her adımda", her_adimda),
                   ("yalnız g/ç adımında", gc_adiminda),
                   ("hiç", hic)):
    tik, ortusen, teslim = dongu(yapici, g)
    print(f"{ad:<24s} {teslim:7d} {tik:5d} {ortusen:8d}")

tik, ortusen = kosum(g, 8, 1)
print(f"{'önceki dersin çizelgesi':<24s} {'':>7s} {tik:5d} {ortusen:8d}")


async def basamak(ad, kere, gunluk):
    """Her yinelemede denetimi olay dongusune birakir."""
    for i in range(kere):
        await asyncio.sleep(0)
        gunluk.append(f"{ad}{i}")


async def sirali():
    """Sirali await: ikinci es yordam birincisi bitmeden baslamaz."""
    gunluk = []
    for ad in ("a", "b"):
        await basamak(ad, 3, gunluk)
    return gunluk


print()
gunluk = asyncio.run(sirali())
print("gerçek olay döngüsü, sıralı await:", " ".join(gunluk))
print(f"teslim noktası {len(gunluk)}, örtüşen adım 0 — "
      f"bırakan var, alan yok")
```

```
girdi/çıktı ağırlıklı yük, seksen adım, tek yuva
teslim noktası            teslim   tik  örtüşen
her adımda                    80    31       49
yalnız g/ç adımında           54    36       44
hiç                            0    80        0
önceki dersin çizelgesi             31       49

gerçek olay döngüsü, sıralı await: a0 a1 a2 b0 b1 b2
teslim noktası 6, örtüşen adım 0 — bırakan var, alan yok
```

## Teslim Sıklığı Örtüşmeyi Belirliyor

Tablo üç satırda tek bir değişkeni değiştiriyor: `await`'in nereye yazıldığı. Adım dizileri
üçünde de aynı, görev sayısı aynı, yuva aynı.

**Her adımda teslim eden** eş yordam **80** kez denetimi bırakıyor ve seksen adımı **31**
tikte bitiriyor; örtüşen adım **49**.

**Yalnız girdi/çıktı adımında teslim eden** eş yordam **54** kez bırakıyor — girdi/çıktı adımı
sayısı kadar. Tik **36**'ya çıkıyor, örtüşen adım **44**'e iniyor. Beş tiklik kayıp, işlemci
adımlarının pes peşe atılmasından geliyor: eş yordam iki girdi/çıktı adımı arasında üç işlemci
adımı taşıyorsa, o üç adımı tek bir sürdürmede yapar ve döngü o sırada kimseye sıra veremez.

**Hiç teslim etmeyen** eş yordam **0** kez bırakıyor ve sonuç **80 tik, 0 örtüşen adım** —
tek akış rejiminin tam olarak kendisi. `async def` ile yazılmış olması hiçbir şey değiştirmiyor.

Üç satırın verdiği sıralama şu: teslim **80 → 54 → 0**, örtüşen adım **49 → 44 → 0**. İlişki
tek yönlü ve üst sınır her satırda korunuyor: **örtüşen adım teslim sayısını hiç geçmiyor.**

Buradan doğrudan bir tasarım sonucu çıkıyor: eşzamansız bir programda örtüşmeyi belirleyen
şey kaç görev başlatıldığı değil, gövdelerin **nerede durduğudur**. `async` sözcüğü bir
teslim noktası üretmez; `await` üretir.

İkinci satırın beş tiklik kaybı ayrıca okunmayı hak ediyor, çünkü gerçek gövdelerin çoğu o
satıra benzer. Kayıp, işlemci adımlarının uzunluğuyla büyür: iki teslim noktası arasında ne
kadar çok adım varsa döngü o kadar uzun meşgul kalır. Bu, eşzamansız kodda uzun hesapların
neden ayrı bir yere taşındığının sayılabilir gerekçesidir — taşınmadıklarında bütün görevleri
birden bekletirler.

## Aynı Çizelge, Başka Kaynak

Tablonun son satırı bir doğrulama taşıyor ve dersin en dikkate değer sayısı orada.

Önceki derslerin çizelgeleyicisi, aynı görevleri sekiz işçi ve tek yuvayla koşturunca **31
tik / 49 örtüşen adım** veriyordu. Her adımda teslim eden eş yordam rejimi de **31 tik / 49
örtüşen adım** veriyor. **İki sayı birebir aynı.**

Aynılık bir tesadüf değil, tanımın sonucu. İş parçacığı rejiminde bir görev ilerledikten sonra
sıra ötekine geçiyordu; kararı çizelgeleyici veriyordu. Eş yordam rejiminde de bir görev bir
adım atıp duruyor ve sıra ötekine geçiyor; kararı **kod** veriyor. Görülen çizelge aynı,
çizelgeyi yazan taraf başka.

Bu, eşzamansız programlamanın ne kazandırdığını da yerine koyuyor. Kazandırdığı şey daha çok
örtüşme değil — üst satır bunu gösteriyor, sayı aynı. Kazandırdığı şey örtüşmenin **kaynağı**:
işletim sisteminden iş parçacığı istemeden, tek akışta, bırakma noktalarını kodda yazarak aynı
çizelgeyi elde etmek. Bedeli de aynı yerde: bırakma noktalarını yazmayı unutan gövde, üçüncü
satıra düşer.

## Bırakan Var, Alan Yok

Son iki satır teslim noktasının **yetmediğini** gösteriyor.

Gerçek olay döngüsünde koşan iki eş yordam var; her biri üç kez denetimi bırakıyor, toplam
**6** teslim noktası. Çıktı `a0 a1 a2 b0 b1 b2`. İkinci eş yordam birincisi bitmeden hiç
ilerlemiyor ve örtüşen adım **0**.

Sebebi `await`'in ne yaptığı: `sirali` gövdesi `basamak("a", ...)` üzerinde bekliyor ve o
bitmeden `basamak("b", ...)` **başlatılmamış** oluyor. Denetim bırakılıyor, ama alacak hazır
bir görev yok; döngü aynı eş yordamı geri sürdürüyor.

Buradan iki koşullu bir kural çıkıyor. Örtüşme için **hem** gövdenin denetimi bırakması **hem
de** o anda ilerlemeye hazır ikinci bir görevin bulunması gerekir. Birincisi `await` ile,
ikincisi eş yordamları döngüye **görev olarak kaydetmekle** sağlanır. İkisinden biri eksikse
tablonun üçüncü satırındaki sonuç çıkar: teslim sayısı kaç olursa olsun, örtüşen adım sıfır.

Bu ayrım, eşzamansız kodda en sık yapılan hatanın da açıklamasıdır: gövde `async` yazılmış,
`await` konmuş, hiçbir şey örtüşmemiştir. Ölçülmesi gereken sayı `await` sayısı değil,
**aynı anda ilerlemeye hazır görev sayısıdır**.

## Teslimin Modelde Sayılmayan Bedeli

Tablonun ilk satırı en çok teslimi ve en çok örtüşmeyi birlikte veriyor; buradan "ne kadar
çok `await` o kadar iyi" sonucu çıkarılabilir. Model bunu doğrular ama model bir şeyi
saymıyor ve bunu yazmak gerekir.

Her teslim bir defter işidir: eş yordamın durumu saklanır, döngünün sırasına geri konur, sonra
yeniden sürdürülür. Modelde bu işin bedeli **sıfır** sayılıyor; sayılan tek şey adımın hangi
tikte atıldığı. Gerçek bir programda teslim bedelsiz değildir ve her adımda teslim eden bir
gövde, kazandığı örtüşmenin bir kısmını deftere geri öder.

Bunun ölçüme etkisi yönlüdür ve okunabilir: **31** tik, eşzamansız rejimden beklenebilecek
kazancın **üst sınırıdır**. Bedel eklendiğinde bu sayı yalnız büyür. İkinci satırdaki **36**
ise iki bedelin arasında duruyor: daha az teslim yazıyor ama işlemci adımlarını pes peşe
attığı için beş tik kaybediyor.

Pratikte yazılan gövdeler ikinci satıra benzer, çünkü `await` bekleyen çağrıların önüne
yazılır, hesap yapan satırların arasına değil. Ölçümün söylediği şey şu: ikinci satır ile
üçüncü satır arasındaki fark — **44** örtüşen adıma karşı **0** — hesap yapan satırların
uzunluğuna değil, aradaki bekleyen çağrının denetimi bırakıp bırakmadığına bağlı. Uzun bir
işlemci bölümü örtüşmeyi biraz azaltır; bırakmayan tek bir çağrı onu sıfırlar.

## Özet

- Eş yordam, çağrıldığında koşmayan ve sürdürüldükçe ilerleyen bir gövdedir; `await` bir
  bekleme değil, denetimin bırakıldığı **teslim noktasıdır**.
- Olay döngüsü ne işçi ne yuva ekler; tek akışta koşar. Örtüşmenin tek kaynağı gövdelerin
  denetimi bırakmasıdır ve **örtüşen adım teslim sayısını geçemez**.
- Aynı seksen adım, teslim her adımda yazıldığında **80 teslim / 31 tik / 49 örtüşen adım**,
  yalnız girdi/çıktı adımında yazıldığında **54 / 36 / 44**, hiç yazılmadığında **0 / 80 / 0**
  verir.
- Her adımda teslim eden eş yordam rejimi, sekiz işçili tek yuvalı çizelgeyle **birebir aynı**
  sayıyı verir; değişen şey çizelge değil, çizelgeyi yazan taraftır.
- Teslim noktası örtüşme için gerekli ama yeterli değildir: sıralı `await` ile koşan iki eş
  yordam **6** kez denetimi bırakır ve **0** örtüşen adım verir.

## Sonraki Adım

Tablonun üçüncü satırı bu dersin sonucu ama bir sonraki dersin sorusu. Gövdenin denetimi hiç
bırakmaması her zaman yazarın tercihi değildir: çağrılan bir işlev bırakmayı bilmiyorsa gövde
onu bekler ve döngü durur. Sonraki ders bunu ölçer — akıştaki bir çağrı denetimi bırakmadığında
örtüşen adım kaç düşer, bütün çağrılar bırakmadığında ne kalır, ve bırakmayı bilmeyen bir
çağrıyı akışa geri sokmanın bedeli kaç adımdır?
