---
title: 'Eşzamanlı Girdi/Çıktı'
source: 'https://academia.sh/tr/kurslar/basarim-ve-izleme/eszamanli-girdi-cikti'
course: 'Başarım Karşıt Kalıpları ve İzleme'
language: tr
updated: '2026-08-17T18:10:59+00:00'
license: 'CC BY-SA 4.0'
---

# Eşzamanlı Girdi/Çıktı

Engelleyen çağrıların kapasiteye etkisinin ölçülmesi: aynı verim tavanını veren iki nedenin bağımlılık doluluğuyla ayrılması (0,9999 ve 0,1819), engelleyen tasarımın verimi eşzamanlılık sınırının bekleme artı iş süresine bölümüyle sınırlaması, aynı verimi taşımak için işçi sayısının 21 kat büyümesi ve düzeltmenin karşılığında uçuştaki isteğin 8'den 46'ya çıkması.

Bir önceki dersin bütün ölçümleri bir sayıyı sabit tuttu: havuzun turda 540 birim işlediği. O
sayının nereden geldiği hiç sorulmadı. Bir sürecin taşıyabileceği iş, işlemcisinin hızıyla değil,
aynı anda kaç isteği ilerletebildiğiyle sınırlıdır.

Belirti şudur: verim turda 0,36 istekte tavan yaptı ve işçi eklemek bu sayıyı büyütmüyor. İşçilerin
doluluğu 0,95 — havuz doymuş görünüyor. Bu ders o görüntünün yanıltıcı olabildiğini gösterir.

## Aynı Belirti, İki Neden

**Birinci neden: aşağı akış doymuş.** Bağımlılık turda ne kadar çağrı karşılayabiliyorsa verim
odur; işçi eklemek hiçbir şeyi değiştirmez, çünkü darboğaz çağıranda değildir.

**İkinci neden: işçiler engelleyen çağrıda bekliyor.** Bağımlılık boşta duruyor, ama her işçi bir
**engelleyen çağrının** (blocking call) yanıtını beklerken başka hiçbir isteği ilerletemez. Buna
**eşzamanlı girdi/çıktı** (synchronous I/O) denir.

İki durumda da işçi doluluğu 1'e yakın çıkar ve iki durumda da işçi eklemek çare gibi görünür.
Ayıran ölçüm işçilerde değil, **bağımlılıkta**dır: bağımlılığın kendi doluluğu 1'e yakınsa neden
birincidir, düşükse ikincidir. Bu ölçüm alınmadan yapılan her açıklama tahmindir.

## Engelleyen Çağrı Gerçekte Ne Yapar

Aşağıdaki blok bir model değil, bu makinede koşan gerçek bir ölçümdür. İki yüz dosya okunur; süre
ölçülmez, çünkü süre bu makineye bağlıdır. Ölçülen nicelikler ikisi de belirlenimlidir: okuma
sürerken **ilerleyen başka iş sayısı** ve **eş zamanlı uçuştaki işlem sayısı**.

```js
// eszamanli/gercek.mjs — gercek node kosumu: engelleyen cagri sirasinda baska hicbir is
// ilerleyemez. Olculen nicelik sure degil, ilerleyen is sayisi ve es zamanli ucustaki islem.
import { mkdtempSync, writeFileSync, readFileSync, rmSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

const N = 200;
const dizin = mkdtempSync(join(tmpdir(), "kk09-"));
for (let i = 0; i < N; i += 1) writeFileSync(join(dizin, `k${i}`), "x".repeat(1024));
const yol = (i) => join(dizin, `k${i}`);

// A: engelleyen cagri. Donguye girmeden once siraya konan is, dongu bitene kadar ilerleyemez.
let ilerleyen = 0, ucus = 0, enBuyukUcusA = 0;
const bekleyenIs = Promise.resolve().then(() => { ilerleyen += 1; });
for (let i = 0; i < N; i += 1) {
  ucus += 1; enBuyukUcusA = Math.max(enBuyukUcusA, ucus);
  readFileSync(yol(i));
  ucus -= 1;
}
console.log(`engelleyen: dongu boyunca ilerleyen baska is = ${ilerleyen},` +
  ` en buyuk es zamanli ucus = ${enBuyukUcusA}, okunan dosya = ${N}`);
await bekleyenIs;

// B: engellemeyen cagri. Ayni is, cagrilar surerken ilerler.
let ilerleyenB = 0, ucusB = 0, enBuyukUcusB = 0;
const bekleyenIsB = Promise.resolve().then(() => { ilerleyenB += 1; });
const sonuc = await Promise.all(Array.from({ length: N }, async (_, i) => {
  ucusB += 1; enBuyukUcusB = Math.max(enBuyukUcusB, ucusB);
  const b = await readFile(yol(i));
  ucusB -= 1;
  return b.length;
}));
await bekleyenIsB;
console.log(`engellemeyen: cagrilar surerken ilerleyen baska is = ${ilerleyenB},` +
  ` en buyuk es zamanli ucus = ${enBuyukUcusB}, okunan dosya = ${sonuc.length}`);
console.log(`es zamanli ucustaki islem orani = ${enBuyukUcusB / enBuyukUcusA}`);
rmSync(dizin, { recursive: true, force: true });
```

```
engelleyen: dongu boyunca ilerleyen baska is = 0, en buyuk es zamanli ucus = 1, okunan dosya = 200
engellemeyen: cagrilar surerken ilerleyen baska is = 1, en buyuk es zamanli ucus = 200, okunan dosya = 200
es zamanli ucustaki islem orani = 200
```

İki sayı bütün mekaniği veriyor. Engelleyen düzende, döngüye girmeden önce sıraya konmuş bir iş
iki yüz okuma bitene kadar **hiç ilerlemiyor** ve aynı anda uçuşta olan işlem sayısı 1'de kalıyor.
Engellemeyen düzende aynı iş çağrılar sürerken ilerliyor ve uçuştaki işlem 200'e çıkıyor: **200
kat**. Burada ölçülen şey koşutluk değildir — çalışma zamanının kaç işi gerçekten koşut yürüttüğü
ayrı bir sorudur. Ölçülen şey, işçinin bloke olup olmadığıdır.

Dil düzeyinde eşzamansız model Eşzamansız JavaScript ve Çalışma Zamanı kursunda kuruldu; burada
yeniden anlatılmaz. Buradaki soru, bu farkın **kapasiteye** ne yaptığıdır.

## İki Nedeni Ayıran İki Ölçüm

Aşağıdaki koşum bir **modeldir**: tur soyut bir adımdır ve gerçek süreç ya da iş parçacığı
kurulmaz. **KK13 — çağrı profili.** Eşzamanlılık sınırı 8 işçi, yerel iş 1 tur, engelleyen
çağrının beklemesi 20 tur. Gerekçe: uzak bir bağımlılığın yanıtı yerel işten iki mertebe uzundur;
duyarlılığı son tabloda bekleme süresi değiştirilerek verilir. **KK14 — çevrim katsayısı.** Bir tur
1 ms sayılır; bu yalnız verimi K01'in istek/s ölçüsüne çevirmek içindir. Bu varsayımlar K01'in
tablosuna eklenmez.

```js
// eszamanli/kapasite.mjs — isci havuzunun MODELI. Tur soyut bir adimdir; KK14 ile bir tur
// 1 ms sayilir (cevrim katsayisi varsayim). Gercek surec ya da is parcacigi kurulmaz.
export const K01 = { tepeUc: 513.89 };

export function kosum({ tur = 20_000, sinir = 8, is = 1, bekleme = 20, bagimlilik = 2.0,
                        engelleyen = true, teklif = 3 }) {
  let bosIsci = sinir, kuyruk = 0, tBirikim = 0, jBirikim = 0;
  const aktif = [];                       // { asama: "is" | "jeton" | "bekle", kalan }
  const s = { tamam: 0, calisan: 0, bekleyen: 0, jeton: 0, enBuyukUcus: 0 };

  for (let t = 1; t <= tur; t += 1) {
    tBirikim += teklif;
    while (tBirikim >= 1) { tBirikim -= 1; kuyruk += 1; }
    jBirikim += bagimlilik;
    let jeton = Math.floor(jBirikim); jBirikim -= jeton;

    while (bosIsci > 0 && kuyruk > 0) { kuyruk -= 1; bosIsci -= 1; aktif.push({ asama: "is", kalan: is }); }

    for (let i = aktif.length - 1; i >= 0; i -= 1) {
      const r = aktif[i];
      if (r.asama === "is") {
        r.kalan -= 1; s.calisan += 1;
        if (r.kalan === 0) r.asama = "jeton";
      } else if (r.asama === "jeton") {
        if (jeton > 0) {
          jeton -= 1; s.jeton += 1; r.asama = "bekle"; r.kalan = bekleme;
          if (!engelleyen) bosIsci += 1;         // isci cagriyi baslatip serbest kalir
        } else if (engelleyen) s.bekleyen += 1;  // jeton yokken isci elde tutuluyor
      } else {
        r.kalan -= 1;
        if (engelleyen) s.bekleyen += 1;
        if (r.kalan === 0) {
          s.tamam += 1; if (engelleyen) bosIsci += 1;
          aktif.splice(i, 1);
        }
      }
    }
    s.enBuyukUcus = Math.max(s.enBuyukUcus, aktif.length);
  }

  const isciTur = s.calisan + s.bekleyen;
  return {
    verim: s.tamam / tur,
    isciDoluluk: isciTur / (sinir * tur),
    beklemePayi: isciTur === 0 ? 0 : s.bekleyen / isciTur,
    bagimlilikDoluluk: s.jeton / (bagimlilik * tur),
    ucus: s.enBuyukUcus,
  };
}
```

```js
// eszamanli/olcum.mjs — ayni belirtiyi veren iki neden, ayirt eden iki olcum ve karsiligi
import { K01, kosum } from "./kapasite.mjs";

const EN = [34, 8, 12, 13, 13, 8];
const yaz = (h) => console.log(h.map((x, i) => (i ? String(x).padStart(EN[i]) : String(x).padEnd(EN[i]))).join(" "));
const cizgi = () => console.log(EN.map((n) => "-".repeat(n)).join(" "));
const satir = (ad, r) => yaz([ad, r.verim.toFixed(4), r.isciDoluluk.toFixed(4),
  r.beklemePayi.toFixed(4), r.bagimlilikDoluluk.toFixed(4), r.ucus]);

const [SINIR, IS, BEKLEME] = [8, 1, 20];
console.log(`eszamanlilik siniri ${SINIR} isci, yerel is ${IS} tur, engelleyen cagrinin beklemesi ${BEKLEME} tur`);
console.log(`aritmetik ust sinir: engelleyen ${SINIR}/(${BEKLEME}+${IS}) = ${(SINIR / (BEKLEME + IS)).toFixed(4)} istek/tur,` +
  ` engellemeyen min(${SINIR}/${IS}, bagimlilik) istek/tur\n`);

yaz(["durum", "verim", "isci dol.", "bekleme payi", "bagim. dol.", "ucus"]);
cizgi();
satir("neden 1: bagimlilik doymus (D=0,35)", kosum({ bagimlilik: 0.35 }));
satir("neden 2: engelleyen cagri (D=2,0)", kosum({ bagimlilik: 2.0 }));
console.log();
satir("neden 1, engellemeyen", kosum({ bagimlilik: 0.35, engelleyen: false }));
satir("neden 2, engellemeyen", kosum({ bagimlilik: 2.0, engelleyen: false }));

const e = kosum({ bagimlilik: 2.0 });
const n = kosum({ bagimlilik: 2.0, engelleyen: false });
console.log(`\nneden 2'de duzeltmenin kazanci: ${e.verim.toFixed(4)} -> ${n.verim.toFixed(4)} istek/tur` +
  ` = ${(n.verim / e.verim).toFixed(2)} kat`);
console.log(`ayni verimi engelleyen tasarimla tasimak icin gereken isci = ${n.verim} x (${BEKLEME}+${IS})` +
  ` = ${(n.verim * (BEKLEME + IS)).toFixed(0)}, yani ${((BEKLEME + IS) / IS).toFixed(0)} kat`);
console.log(`karsiliginda buyuyen ucustaki istek: ${e.ucus} -> ${n.ucus} (${(n.ucus / e.ucus).toFixed(2)} kat)` +
  ` ve bagimlilik dolulugu ${e.bagimlilikDoluluk.toFixed(4)} -> ${n.bagimlilikDoluluk.toFixed(4)}`);

// KK14: bir tur 1 ms sayilir; verim istek/s'ye cevrilir ve K01'in tepe hiziyla karsilastirilir.
const TUR_MS = 1;
const saniye = (r) => (r.verim * 1000) / TUR_MS;
console.log(`\nbir tur ${TUR_MS} ms (KK14): tek surecin tasidigi istek engelleyen ${saniye(e).toFixed(2)} istek/s,` +
  ` engellemeyen ${saniye(n).toFixed(2)} istek/s`);
console.log(`K01 tepe ucta ${K01.tepeUc} istek/s -> gereken surec sayisi ` +
  `${Math.ceil(K01.tepeUc / saniye(e))} ve ${Math.ceil(K01.tepeUc / saniye(n))}`);

console.log(`\nisci eklemenin engelleyen tasarimdaki etkisi (D=2,0):`);
yaz(["durum", "verim", "isci dol.", "bekleme payi", "bagim. dol.", "ucus"]);
cizgi();
for (const sinir of [8, 16, 42, 84]) satir(`sinir ${sinir} isci`, kosum({ sinir, bagimlilik: 2.0 }));

console.log(`\nKK13'un duyarliligi: bekleme kisaldikca engelleyen tasarimin bedeli (D=2,0)`);
for (const bekleme of [20, 5, 2, 1]) {
  const a = kosum({ bekleme, bagimlilik: 2.0 }), b = kosum({ bekleme, bagimlilik: 2.0, engelleyen: false });
  console.log(`  bekleme ${String(bekleme).padStart(2)} tur -> engelleyen ${a.verim.toFixed(4)},` +
    ` engellemeyen ${b.verim.toFixed(4)}, oran ${(b.verim / a.verim).toFixed(2)}`);
}
```

```
eszamanlilik siniri 8 isci, yerel is 1 tur, engelleyen cagrinin beklemesi 20 tur
aritmetik ust sinir: engelleyen 8/(20+1) = 0.3810 istek/tur, engellemeyen min(8/1, bagimlilik) istek/tur

durum                                 verim    isci dol.  bekleme payi   bagim. dol.     ucus
---------------------------------- -------- ------------ ------------- ------------- --------
neden 1: bagimlilik doymus (D=0,35)   0.3496       0.9562        0.9542        0.9999        8
neden 2: engelleyen cagri (D=2,0)    0.3635       0.9545        0.9524        0.1819        8

neden 1, engellemeyen                0.3496       0.0438        0.0000        0.9999       15
neden 2, engellemeyen                1.9979       0.2500        0.0000        1.0000       46

neden 2'de duzeltmenin kazanci: 0.3635 -> 1.9979 istek/tur = 5.50 kat
ayni verimi engelleyen tasarimla tasimak icin gereken isci = 1.9979 x (20+1) = 42, yani 21 kat
karsiliginda buyuyen ucustaki istek: 8 -> 46 (5.75 kat) ve bagimlilik dolulugu 0.1819 -> 1.0000

bir tur 1 ms (KK14): tek surecin tasidigi istek engelleyen 363.50 istek/s, engellemeyen 1997.90 istek/s
K01 tepe ucta 513.89 istek/s -> gereken surec sayisi 2 ve 1

isci eklemenin engelleyen tasarimdaki etkisi (D=2,0):
durum                                 verim    isci dol.  bekleme payi   bagim. dol.     ucus
---------------------------------- -------- ------------ ------------- ------------- --------
sinir 8 isci                         0.3635       0.9545        0.9524        0.1819        8
sinir 16 isci                        0.7267       0.9544        0.9524        0.3636       16
sinir 42 isci                        1.9071       0.9542        0.9524        0.9545       42
sinir 84 isci                        1.9979       0.9755        0.9756        1.0000       82

KK13'un duyarliligi: bekleme kisaldikca engelleyen tasarimin bedeli (D=2,0)
  bekleme 20 tur -> engelleyen 0.3635, engellemeyen 1.9979, oran 5.50
  bekleme  5 tur -> engelleyen 1.1426, engellemeyen 1.9994, oran 1.75
  bekleme  2 tur -> engelleyen 1.9997, engellemeyen 1.9997, oran 1.00
  bekleme  1 tur -> engelleyen 1.9998, engellemeyen 1.9998, oran 1.00
```

Uçuş sayıları ve ilerleyen iş sayısı **ölçüm**, model çıktısındaki verim ve doluluklar belirlenimli
koşumdan çıkan **hesap**, çağrı profili ve çevrim katsayısı **varsayım** sınıfındadır.

## Ölçüm Nedeni Söylüyor

İlk tablonun iki satırı aynı belirtiyi veriyor: verim 0,3496 ile 0,3635, işçi doluluğu 0,9562 ile
0,9545, bekleme payı 0,9542 ile 0,9524. İşçiler doymuş görünüyor ve iki durumda da vakitlerinin
yüzde doksan beşi bekleyerek geçiyor.

Ayrım son sütundan bir öncekinde. Birinci nedende bağımlılık doluluğu **0,9999** — bağımlılık
gerçekten doymuş. İkinci nedende **0,1819** — bağımlılık kapasitesinin beşte dördü boşta dururken
verim tavana çarpıyor. Tek başına işçi doluluğuna bakan bir tanı iki durumu ayıramaz; bağımlılığın
kendi doluluğu ayırır.

Doğrulaması ikinci tablodadır. Engelleyen çağrı kaldırıldığında birinci nedende hiçbir şey
değişmiyor (0,3496 → 0,3496), ikinci nedende verim 0,3635'ten **1,9979**'a, yani 5,50 kata
çıkıyor. Aynı düzeltme bir nedende işe yarar, ötekinde yaramaz — bu yüzden ölçüm düzeltmeden önce
gelir.

Tavanın kaynağı aritmetiktir ve ilk satırda yazılı: engelleyen tasarımda verim, eşzamanlılık
sınırının bekleme artı iş süresine bölümünü aşamaz — 8 / (20 + 1) = 0,3810. Model 0,3635 ölçüyor;
aradaki fark bağımlılığın jeton dağıtımının turlara yayılmasından gelir.

Üçüncü tablo işçi eklemenin ne yaptığını gösteriyor. Sınır 8'den 16'ya çıkınca verim 0,7267'ye,
42'ye çıkınca 1,9071'e ulaşıyor; yani engelleyen tasarım aynı verimi ancak **21 kat** işçiyle
taşıyor. İşçi doluluğu bu satırların hepsinde 0,95 civarında kalıyor — doluluk hiçbir zaman sorunu
göstermiyor, yalnız işçilerin meşgul olduğunu söylüyor.

## Düzeltmenin Karşılığında Büyüyen

Engellemeyen tasarım bedava değildir ve bedeli sayılabilir.

**Uçuştaki istek.** Aynı anda sistemde duran istek sayısı 8'den 46'ya çıkıyor: 5,75 kat. Her
uçuştaki istek bellek tutar — tampon, bağlam, kısmi yanıt. Engelleyen tasarımda bu sayıyı
eşzamanlılık sınırı kendiliğinden bağlıyordu; engellemeyen tasarımda böyle bir sınır yoktur ve
kabul denetimi ayrıca konmalıdır. Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunun kabul
denetimi ve eşzamanlılık sınırı dersleri tam olarak bu boşluğu doldurur.

**Darboğazın yer değiştirmesi.** Bağımlılık doluluğu 0,1819'dan 1,0000'e çıkıyor. Çağıran
düzeldiğinde yük bağımlılığa iniyor ve bir sonraki tanı orada yapılacaktır.

**Taşınan istek.** KK14 ile bir tur 1 ms sayıldığında tek süreç engelleyen tasarımda 363,50
istek/s, engellemeyen tasarımda 1997,90 istek/s taşıyor. K01'in 513,89 istek/s tepe hızı için
gereken süreç sayısı 2 ile 1 arasında değişiyor: aynı donanım, iki kat fark.

## Engelleyen Çağrının Doğru Olduğu Koşul

Son tablo sınırı veriyor. Bedel, beklemenin yerel işe oranından doğar. Bekleme 20 turken oran 5,50;
5 turken 1,75; 2 turken **1,00**. Bekleme yerel işle aynı mertebeye indiğinde engelleyen tasarım
hiçbir şey kaybettirmez, çünkü işçinin tuttuğu süre zaten çalışarak geçiyordur.

İkinci koşul birinci nedenden çıkar: bağımlılık doymuşsa engellememenin kazancı sıfırdır (0,3496 →
0,3496). Darboğaz aşağıdaysa çağıranı karmaşıklaştırmak yalnız uçuştaki isteği büyütür.

## Özet

- Belirti verimin tavana çarpması ve işçi eklemenin işe yaramamasıdır; iki nedeni vardır — aşağı
  akış doymuştur ya da işçiler engelleyen çağrıda beklemektedir.
- İşçi doluluğu iki nedeni ayıramaz: 0,9562 ile 0,9545, bekleme payı 0,9542 ile 0,9524. Ayıran
  ölçüm bağımlılığın kendi doluluğudur — 0,9999 ile 0,1819.
- Engelleyen tasarımda verim, eşzamanlılık sınırının bekleme artı iş süresine bölümünü aşamaz:
  8 / (20 + 1) = 0,3810 istek/tur; aynı verimi taşımak için işçi sayısı 21 kat büyümelidir.
- Düzeltme ikinci nedende verimi 0,3635'ten 1,9979'a (5,50 kat) çıkarıyor, birinci nedende hiçbir
  şeyi değiştirmiyor; bir tur 1 ms sayıldığında tek süreç 363,50 yerine 1997,90 istek/s taşıyor.
- Karşılığında uçuştaki istek 8'den 46'ya (5,75 kat) çıkıyor ve bağımlılık doluluğu 0,1819'dan
  1,0000'e yükseliyor: sınır kalktığı için kabul denetimi ayrıca konmalıdır.
- Engelleyen çağrı, bekleme yerel işle aynı mertebedeyken doğrudur: bekleme 2 turda oran 1,00'e
  iniyor.

## Sonraki Adım

Dokuz kalıbın hepsi bir varsayımın üstünde duruyor: bir isteğin bir kez yapıldığı. Uçtan gelen yük
dışarıdan belirlenir, sistem onu yalnız taşır. Bu varsayım bir şey bozulduğu anda düşer. Çağrılar
başarısız olmaya başladığında çağıran yeniden dener, denemeler zincirin her katmanında çarpılır ve
bağımlılığa varan yük artık dışarıdan değil, sistemin kendisinden gelir. Sonraki ders konunun son
tanısıdır ve sorusu şudur: böyle bir döngü dışarıdan nasıl görünür. Bağımlılığa varan çağrı hızının
iki katına çıkması hem gerçek bir talep artışının hem de bir yeniden deneme fırtınasının belirtisi
olabilir; ikisini ayıran ölçüt çağrı sayısı değildir.
