---
title: 'Önbellek ve Paralellik'
source: 'https://academia.sh/tr/kurslar/ci-cd/onbellek-ve-paralellik'
course: 'Sürekli Tümleştirme ve Teslimat'
language: tr
updated: '2026-08-17T18:09:02+00:00'
license: 'CC BY-SA 4.0'
---

# Önbellek ve Paralellik

Hattın kendi süresi ölçülür: aşama önbelleği gerçek dosyaların içerik özetinden anahtar üretir, on iki koşumluk bir dizide önbellekli ve önbelleksiz süre, isabet oranı ve isabetin değişiklik türüne göre dağılımı sayılır, ardından paralellik uygulanıp kritik yolun koyduğu sınır gösterilir.

Önceki ders hattın ürettiği çıktıyı sürümledi ve sakladı: her koşumun çıktısı kendi kimliğiyle
duruyor, hangi değişiklikten doğduğu okunabiliyor. Bir şey hiç sayılmadı — o çıktının kaç dakikada
üretildiği. Hat her koşumda bütün aşamaları baştan koşturuyor, oysa aşamaların çoğunun girdisi iki
koşum arasında hiç değişmiyor.

Bu ders hattın kendi süresini ölçer. Elde iki kaldıraç var: aynı girdiyle aynı işi yapan aşamayı
bir daha koşturmamak — **aşama önbelleği** — ve birbirine bağlı olmayan aşamaları aynı anda
koşturmak — **paralellik**. İkisinin de sınırı vardır ve sınırlar aynı yerde durmaz. Kapı ölçüsü
burada iki uçludur: bir aşama önbellekten geldiğinde o kapı **hiç koşmaz**, ve kapının kaçırdığı
tam olarak orada doğar.

**HT25.** Hat `node` ile kurulan bir modeldir. Aşama süreleri modelin bildirdiği nominal
değerlerdir, koşum makinesinden ölçülmez; ortamdan bağımsız nicelikler koşan aşama sayısı, isabet
sayısı ve önbellek girdisidir. **HT26.** Aşama anahtarı gerçek dosyalardan hesaplanır: dosyalar
diske yazılır, okunur, özetlenir. **HT27.** Değişiklik dizisi kurgu bölgesel ölçüm ağının iki
haftalık düzeltme akışını temsil eder; rastgelelik yoktur, dizi elle yazılmıştır. **HT28.** Kusur
kümesi sekiz kusurdur ve her kusurun hangi kapılarda yakalanabileceği bildirilmiştir; koşan kapı
kendi kusurunu yakalar, koşmayan kapı yakalamaz. **HT29.** Önbellek girdileri silinmez, saklama
kuralı uygulanmaz. **HT30.** Çalıştırıcılar özdeştir ve kuyrukta bekleme sıfırdır — o kalem sonraki
derste ölçülür.

İmaj katmanlarının önbelleği bu kursun dışında ölçüldü ve tekrarlanmaz; burada ölçülen birim
**hat aşamasıdır** — kendi girdisi, kendi süresi ve kendi çıktısı olan bir iş adımı.

## Aşama Anahtarı

Önbelleğin tek kuralı vardır: **bir aşamanın anahtarı, o aşamanın sonucunu değiştirebilecek her
şeyi kapsamalıdır.** Kapsanmayan bir girdi değiştiğinde anahtar aynı kalır, aşama koşmaz ve hat
eski sonucu doğru sanır. Modelde her aşama girdilerini kendisi **bildirir**.

```js
// olcum-agi/hat.mjs — hat asamalari ve asama onbellegi (model)
import { mkdirSync, writeFileSync, readFileSync, readdirSync, statSync, appendFileSync, rmSync } from "node:fs";
import { createHash } from "node:crypto";

const KOK = "proje";
const ozet = (s) => createHash("sha256").update(s).digest("hex").slice(0, 12);
const metin = (ad, n) => Array.from({ length: n }, (_, i) => `// ${ad} ${i}\n`).join("");
const AGAC = {
  "bagimlilik-listesi": "olcum-istemcisi 3.1\nkuyruk-baglayici 1.9\ncsv-cozumleyici 2.4\n",
  "kaynak/toplayici.js": metin("toplayici", 260), "kaynak/dogrulayici.js": metin("dogrulayici", 180),
  "kaynak/faturalama.js": metin("faturalama", 240), "sinama/birim/toplayici.js": metin("birim", 300),
  "sinama/tumlesim/akis.js": metin("tumlesim", 220), "sinama/sozlesme/api.js": metin("sozlesme", 90),
  "yapilandirma/ortam.json": '{"zaman-asimi":30}\n', "kurallar/statik.json": '{"kural-sayisi":48}\n',
  "sozlesmeler/api.json": '{"alan-sayisi":17}\n',
};

// sure: bildirilmis nominal asama suresi (saniye). taban: onbellege yazilan cikti (bayt).
// girdi: asamanin BILDIRDIGI girdiler — kurallar/ ve sozlesmeler/ hicbir asamada bildirilmemistir.
export const ASAMALAR = [
  { ad: "bagimlilik-cozumu", girdi: ["bagimlilik-listesi"], onceki: [], sure: 42, taban: 41e6 },
  { ad: "derleme", girdi: ["kaynak"], onceki: ["bagimlilik-cozumu"], sure: 65, taban: 8.6e6 },
  { ad: "statik-cozumleme", girdi: ["kaynak"], onceki: ["bagimlilik-cozumu"], sure: 27, taban: 12e4 },
  { ad: "birim-sinamasi", girdi: ["sinama/birim"], onceki: ["derleme"], sure: 38, taban: 9e4 },
  { ad: "tumlesim-sinamasi", girdi: ["sinama/tumlesim", "yapilandirma"], onceki: ["derleme"], sure: 96, taban: 26e4 },
  { ad: "paketleme", girdi: ["yapilandirma"], onceki: ["derleme"], sure: 18, taban: 9.1e6 },
  { ad: "sozlesme-sinamasi", girdi: ["sinama/sozlesme"], onceki: ["paketleme"], sure: 31, taban: 6e4 },
  { ad: "imaj-uretimi", girdi: [], onceki: ["paketleme"], sure: 24, taban: 12.3e6 },
];
export const GERI_YUKLEME = 2; // her isabette ciktinin onbellekten geri yuklenme suresi (saniye)
export const SERI = ASAMALAR.reduce((t, a) => t + a.sure, 0);

export const kurAgac = () => {
  rmSync(KOK, { recursive: true, force: true });
  for (const [y, i] of Object.entries(AGAC)) {
    mkdirSync(`${KOK}/${y}`.split("/").slice(0, -1).join("/"), { recursive: true });
    writeFileSync(`${KOK}/${y}`, i);
  }
};
export const degistir = (yol, no) => appendFileSync(`${KOK}/${yol}`, `// duzeltme ${no}\n`);
const gez = (alt) => readdirSync(`${KOK}/${alt}`, { withFileTypes: true })
  .flatMap((g) => (g.isDirectory() ? gez(`${alt}/${g.name}`) : [`${alt}/${g.name}`])).sort();
const yollari = (g) => (statSync(`${KOK}/${g}`).isDirectory() ? gez(g) : [g]);

// Asama anahtari: asama adi + bildirilen girdilerin gercek icerigi + onceki asamalarin anahtarlari.
export const kosturHat = (onbellek) => {
  const anahtar = {}, sonuc = { isabet: [], kosan: [], sure: 0 };
  for (const a of ASAMALAR) {
    const dosyalar = a.girdi.flatMap(yollari);
    anahtar[a.ad] = ozet(a.ad + dosyalar.map((y) => y + readFileSync(`${KOK}/${y}`)).join() +
      a.onceki.map((o) => anahtar[o]).join());
    if (onbellek.has(anahtar[a.ad])) { sonuc.isabet.push(a.ad); sonuc.sure += GERI_YUKLEME; continue; }
    onbellek.set(anahtar[a.ad], a.taban + dosyalar.reduce((t, y) => t + statSync(`${KOK}/${y}`).size, 0));
    sonuc.kosan.push(a.ad); sonuc.sure += a.sure;
  }
  return sonuc;
};
```

Anahtara önceki aşamaların anahtarlarının girmesi bir zincir kurar: bir aşama ıskaladığında ona
bağlı **her** aşama da ıskalar, kendi girdisi değişmemiş olsa bile. Bu önbelleğin doğru tarafıdır;
yanlış tarafı bildirim listesindedir — `kurallar/` ve `sozlesmeler/` hattın gerçek girdileridir ama
hiçbir aşama onları bildirmez.

## On İki Koşum

Dizi on iki koşumda kurgu ağın bir düzeltme akışını yürütür: kaynak ve sınama değişiklikleri, bir
bağımlılık listesi, bir yapılandırma, hiçbir şeyin değişmediği bir koşum ve bildirilmemiş dizinlere
dokunan iki değişiklik. Sekiz kusur diziye serpiştirilmiştir.

```js
// olcum-agi/kosum.mjs — on iki koşumluk degisiklik dizisi, onbellekli ve onbelleksiz
import { kurAgac, degistir, kosturHat, ASAMALAR, SERI } from "./hat.mjs";

// Kurgu iki haftalik dizi: dokunulan dosya, degisiklik turu, tasidigi kusur, kusuru
// yakalayabilecek kapilar. Rastgelelik yok; dizi elle yazilmistir.
const DIZI = [
  ["", "ilk kosum"], ["kaynak/toplayici.js", "kaynak", "K1", ["birim-sinamasi", "tumlesim-sinamasi"]],
  ["kaynak/dogrulayici.js", "kaynak", "K2", ["statik-cozumleme"]], ["sinama/birim/toplayici.js", "sinama"],
  ["", "degisiklik yok"], ["bagimlilik-listesi", "bagimlilik", "K3", ["tumlesim-sinamasi"]],
  ["kurallar/statik.json", "kural", "K4", ["statik-cozumleme"]],
  ["kaynak/faturalama.js", "kaynak", "K5", ["birim-sinamasi", "statik-cozumleme"]],
  ["yapilandirma/ortam.json", "yapilandirma"], ["sozlesmeler/api.json", "sozlesme", "K6", ["sozlesme-sinamasi"]],
  ["sinama/tumlesim/akis.js", "sinama", "K7", ["tumlesim-sinamasi"]],
  ["kaynak/toplayici.js", "kaynak", "K8", ["birim-sinamasi"]],
];

kurAgac();
const onbellek = new Map(), tur = {}, kacan = [];
const kapi = Object.fromEntries(ASAMALAR.map((a) => [a.ad, { kosum: 0, sure: 0, tuttu: 0, yalniz: 0 }]));
let topIsabet = 0, topSure = 0;

console.log(" no  degisiklik".padEnd(32) + "tur".padEnd(15) + "isabet kosan sure(s)");
DIZI.forEach(([dosya, t, kusur, yakalayan], i) => {
  if (dosya) degistir(dosya, i);
  const s = kosturHat(onbellek);
  topIsabet += s.isabet.length; topSure += s.sure;
  tur[t] = tur[t] || { deneme: 0, isabet: 0 };
  tur[t].deneme += ASAMALAR.length; tur[t].isabet += s.isabet.length;
  for (const ad of s.kosan) { kapi[ad].kosum++; kapi[ad].sure += ASAMALAR.find((a) => a.ad === ad).sure; }
  if (kusur) {
    const tutan = yakalayan.filter((y) => s.kosan.includes(y));
    if (!tutan.length) kacan.push(kusur);
    else for (const y of tutan) { kapi[y].tuttu++; if (tutan.length === 1) kapi[y].yalniz++; }
  }
  console.log(`  ${String(i + 1).padStart(2)}  ${dosya || "(" + t + ")"}`.padEnd(32) + t.padEnd(15) +
    String(s.isabet.length).padStart(4) + String(s.kosan.length).padStart(6) + String(s.sure).padStart(7));
});

const deneme = DIZI.length * ASAMALAR.length, onbelleksiz = DIZI.length * SERI;
console.log(`\nonbelleksiz ${onbelleksiz} s, onbellekli ${topSure} s (%${(100 - (topSure * 100) / onbelleksiz).toFixed(1)} kisalma); ` +
  `isabet ${topIsabet}/${deneme} (%${((topIsabet * 100) / deneme).toFixed(1)}); ` +
  `onbellek ${onbellek.size} girdi ${([...onbellek.values()].reduce((a, b) => a + b, 0) / 1e6).toFixed(1)} MB`);
console.log("\nisabet / degisiklik turu" + " ".repeat(9) + "kapi          kosum  sure  tuttugu  yalniz");
const satir = Object.entries(tur).map(([t, d]) => `  ${t.padEnd(15)}${d.isabet}/${d.deneme} %${((d.isabet * 100) / d.deneme).toFixed(0)}`);
ASAMALAR.forEach((a, i) => {
  const k = kapi[a.ad];
  console.log((satir[i] || "").padEnd(33) + a.ad.padEnd(19) + String(k.kosum).padStart(3) +
    String(k.sure + "s").padStart(7) + String(k.tuttu).padStart(7) + String(k.yalniz).padStart(8));
});
console.log(`\nkusur kumesi 8, kacan ${kacan.length}: ${kacan.join(", ")} — bildirilmemis girdi, bayat isabet`);
```

```
 no  degisiklik                 tur            isabet kosan sure(s)
   1  (ilk kosum)               ilk kosum         0     8    341
   2  kaynak/toplayici.js       kaynak            1     7    301
   3  kaynak/dogrulayici.js     kaynak            1     7    301
   4  sinama/birim/toplayici.js sinama            7     1     52
   5  (degisiklik yok)          degisiklik yok    8     0     16
   6  bagimlilik-listesi        bagimlilik        0     8    341
   7  kurallar/statik.json      kural             8     0     16
   8  kaynak/faturalama.js      kaynak            1     7    301
   9  yapilandirma/ortam.json   yapilandirma      4     4    177
  10  sozlesmeler/api.json      sozlesme          8     0     16
  11  sinama/tumlesim/akis.js   sinama            7     1    110
  12  kaynak/toplayici.js       kaynak            1     7    301

onbelleksiz 4092 s, onbellekli 2273 s (%44.5 kisalma); isabet 46/96 (%47.9); onbellek 50 girdi 287.5 MB

isabet / degisiklik turu         kapi          kosum  sure  tuttugu  yalniz
  ilk kosum      0/8 %0          bagimlilik-cozumu    2    84s      0       0
  kaynak         4/32 %13        derleme              6   390s      0       0
  sinama         14/16 %88       statik-cozumleme     6   162s      2       1
  degisiklik yok 8/8 %100        birim-sinamasi       7   266s      3       1
  bagimlilik     0/8 %0          tumlesim-sinamasi    8   768s      3       2
  kural          8/8 %100        paketleme            7   126s      0       0
  yapilandirma   4/8 %50         sozlesme-sinamasi    7   217s      0       0
  sozlesme       8/8 %100        imaj-uretimi         7   168s      0       0

kusur kumesi 8, kacan 2: K4, K6 — bildirilmemis girdi, bayat isabet
```

## İsabetin Okunması

Toplam süre **4 092 saniyeden 2 273 saniyeye** iner: yüzde 44,5 kısalma, 96 aşama denemesinde 46
isabet. Bu tek sayı hiçbir karar taşımaz; kararı türe göre dağılım verir.

Sınama değişikliklerinde isabet **yüzde 88'dir** — bir sınama dosyasına dokunmak yalnız o sınama
aşamasını koşturur. Kaynak değişikliklerinde isabet **yüzde 13'e** düşer: kaynak zincirin
dibindedir, ona dokunulduğunda yedi aşama yeniden koşar. Bağımlılık listesi değişikliğinde isabet
**sıfırdır**; o dosya en alttaki aşamanın girdisidir ve hattın tamamını geçersizleştirir. Kazanç
hattın hangi katmanına ne sıklıkla dokunulduğuna bağlıdır.

Yüzde 100 gösteren üç satırdan yalnız biri doğrudur. Hiçbir şeyin değişmediği koşumda sekiz
aşamanın sekizi isabet eder ve hat 16 saniyede biter; önbelleğin yapması gereken tam olarak budur.
Kural ve sözleşme değişikliklerinde de sekiz isabet görünür — ama orada bir şey değişmiştir.
`kurallar/statik.json` statik çözümlemenin kural kümesi, `sozlesmeler/api.json` sözleşme
sınamasının ölçütüdür; ikisi de hiçbir aşamanın bildirdiği girdi değildir. Anahtar değişmez, kapı
koşmaz, hat yeşil biter. **En yüksek isabet oranını veren iki değişiklik türü, önbelleğin
görmediği türdür.**

Kapı hesabı bunun bedelini yazar. Sekiz kusurdan altısı yakalanır, **ikisi kaçar**: K4 kural
kümesinin sıkılaştırılmasıyla görünür hâle gelen kusurdur, K6 sözleşme alanının değişmesinden
doğar; ikisi de yakalanabilecekleri kapı önbellekten geldiği için geçer. Marjinal değer sütunu
kapıları ayırır: tümleşim sınaması sekiz koşumda **768 saniye** harcar, üç kusur tutar ve bunların
**ikisini yalnız kendisi** yakalar — hattın en pahalı ve en gerekli kapısıdır. Birim sınaması 266
saniyede üç kusur tutar ama yalnız birini tek başına; öteki ikisini tümleşim sınaması da
yakalardı. Dört aşama — bağımlılık çözümü, derleme, paketleme, imaj üretimi — hiç kusur tutmaz;
onlar kapı değil üretim adımıdır ve bu hesaba girmez.

Bildirim düzeltilirse bedel tablodan okunur: yedinci koşumda statik çözümleme 2 saniyelik isabet
yerine 27 saniye, onuncu koşumda sözleşme sınaması 2 yerine 31 saniye alır. Toplam **54 saniye**,
önbellekli sürenin yüzde 2,4'ü — karşılığında iki kusur kaçmaz.

Önbelleğin kendi bedeli üç kalemdir. Depo: on iki koşumda **50 girdi ve 287,5 MB** birikir,
hiçbiri silinmez. Geri yükleme: 46 isabetin her biri 2 saniye ödetir, toplam **92 saniye**.
Üçüncüsü sayıya gelmez ve en pahalısıdır — yukarıdaki iki kaçan kusur, geçersizleşme hatasının
faturasıdır.

## Kritik Yol

Önbellek tekrarlanan işi kaldırdı; kalan iş hâlâ tek sırada koşuyor. Aşamalar bir bağımlılık
çizgesi kurar, birbirine bağlı olmayanlar aynı anda koşabilir ve sınırı çizgenin en uzun zinciri
belirler.

```js
// olcum-agi/paralel.mjs — asama cizgesi, calistirici sayisi ve kritik yol
import { ASAMALAR, GERI_YUKLEME } from "./hat.mjs";

const bul = (ad) => ASAMALAR.find((a) => a.ad === ad);
const ardil = (ad) => ASAMALAR.filter((b) => b.onceki.includes(ad));
// Bir asamadan hattin sonuna kalan en uzun sure. Kritik yol, basi en buyuk olan zincirdir.
const kalan = (a) => a.sure + Math.max(0, ...ardil(a.ad).map(kalan));
const zincir = (a) => (ardil(a.ad).length
  ? `${a.ad}(${a.sure}) -> ` + zincir(ardil(a.ad).reduce((x, y) => (kalan(x) >= kalan(y) ? x : y))) : `${a.ad}(${a.sure})`);

// Liste cizelgelemesi: oncekileri BITMIS asamalar arasindan kalan yolu en uzun olan,
// bosalan calistiriciya verilir. Calistirici sayisi n.
const cizelgele = (sure, n) => {
  const biten = new Set(), suren = [], bekleyen = ASAMALAR.map((a) => a.ad);
  let saat = 0;
  while (biten.size < ASAMALAR.length) {
    const hazir = bekleyen.filter((ad) => bul(ad).onceki.every((o) => biten.has(o)))
      .sort((x, y) => kalan(bul(y)) - kalan(bul(x)));
    while (suren.length < n && hazir.length) {
      const ad = hazir.shift();
      bekleyen.splice(bekleyen.indexOf(ad), 1);
      suren.push({ ad, biter: saat + sure(ad) });
    }
    saat = Math.min(...suren.map((s) => s.biter));
    for (let i = suren.length - 1; i >= 0; i--) if (suren[i].biter <= saat) { biten.add(suren[i].ad); suren.splice(i, 1); }
  }
  return saat;
};

const bas = ASAMALAR.filter((a) => !a.onceki.length).reduce((x, y) => (kalan(x) >= kalan(y) ? x : y));
const sinir = kalan(bas), seri = ASAMALAR.reduce((t, a) => t + a.sure, 0);
const soguk = (ad) => bul(ad).sure;
// Kaynak degisikliginde onbellek yalniz bagimlilik-cozumunde isabet eder (yukaridaki tablo, 2. kosum).
const isabetli = (ad) => (ad === "bagimlilik-cozumu" ? GERI_YUKLEME : bul(ad).sure);

console.log(`seri ${seri} s, kritik yol ${sinir} s: ${zincir(bas)}`);
console.log("\ncalistirici   soguk  kritik yola uzaklik  ek calistiricinin kazanci  onbellekli (kaynak degisikligi)");
let onceki = null;
for (let n = 1; n <= 6; n++) {
  const s = cizelgele(soguk, n);
  console.log(String(n).padStart(9) + String(s + " s").padStart(9) + String(s - sinir + " s").padStart(18) +
    (onceki === null ? "-" : onceki - s + " s").padStart(24) + String(cizelgele(isabetli, n) + " s").padStart(28));
  onceki = s;
}
```

```
seri 341 s, kritik yol 203 s: bagimlilik-cozumu(42) -> derleme(65) -> tumlesim-sinamasi(96)

calistirici   soguk  kritik yola uzaklik  ek calistiricinin kazanci  onbellekli (kaynak degisikligi)
        1    341 s             138 s                       -                       301 s
        2    218 s              15 s                   123 s                       178 s
        3    203 s               0 s                    15 s                       163 s
        4    203 s               0 s                     0 s                       163 s
        5    203 s               0 s                     0 s                       163 s
        6    203 s               0 s                     0 s                       163 s
```

İkinci çalıştırıcı **123 saniye** kazandırır, üçüncüsü **15 saniye**, dördüncüsü **sıfır**. Süre üç
çalıştırıcıda düzleşip 203 saniyede durur; bu sayı çalıştırıcı sayısından değil çizgeden gelir.
Sınırı koyan zincir bağımlılık çözümü, derleme ve tümleşim sınamasıdır: 42 + 65 + 96. Üçü birbirini
beklemek zorundadır, dolayısıyla hiçbir çalıştırıcı sayısı hattı 203 saniyenin altına indiremez. En
yüksek hızlanma **1,68 kattır** ve dördüncü çalıştırıcıdan sonrası ödenmiş boş kapasitedir.

Sınırı aşmanın tek yolu zinciri kısaltmaktır: tümleşim sınaması iki bağımsız parçaya bölünürse
kritik yol 42 + 65 + 48'e iner. Bu bir hat tasarımı kararıdır, çalıştırıcı satın alma kararı
değildir.

İki kaldıraç birbirini çarpar ama aynı yerden tutmaz. Son sütun kaynak değişikliği koşumunu
gösterir: önbellek zincirin başındaki 42 saniyeyi 2'ye indirir, üç çalıştırıcıyla süre **163
saniyeye** oturur. Önbellek zincirin **başını** kısaltır, paralellik zincirin **dışındaki** işi
kaldırır; ikisi de ortadaki 65 ve 96 saniyeye dokunamaz. Hattın gerçek tabanı orasıdır.

## Özet

- Aşama anahtarı, aşamanın **bildirdiği** girdilerin içeriği ile önceki aşamaların anahtarlarından
  türer. Bildirilmeyen girdi değiştiğinde anahtar değişmez, kapı koşmaz ve hat yeşil biter.
- Önbellek on iki koşumda süreyi 4 092 saniyeden 2 273 saniyeye indirdi (yüzde 44,5), isabet 96
  denemede 46 oldu. Dağılım kararı taşır: sınamada yüzde 88, kaynakta yüzde 13, bağımlılık
  listesinde sıfır.
- Kural ve sözleşme değişikliklerinde görünen yüzde 100 isabet, önbelleğin körlüğüdür. İki kusur
  (K4, K6) yakalanabilecekleri kapı önbellekten geldiği için kaçtı; bildirimin düzeltilmesi on iki
  koşuma 54 saniye, yani yüzde 2,4 ekliyor.
- Kapıların marjinal değeri eşit değildir: tümleşim sınaması 768 saniyede üç kusur tuttu, ikisini
  yalnız kendisi; birim sınaması 266 saniyede üç kusur tuttu ama yalnız birini tek başına.
  Önbelleğin bedeli ise 50 girdi, 287,5 MB depo ve 92 saniyelik geri yüklemedir.
- Paralellik hattı 203 saniyenin altına indiremez. Sınırı bağımlılık çözümü → derleme → tümleşim
  sınaması zinciri koyar; üçüncü çalıştırıcıdan sonra ek çalıştırıcının kazancı sıfırdır.

## Sonraki Adım

Bu ölçüm iki şeyi bedava saydı. Kırk altı isabetin her biri, önceki koşumun çıktısını hâlâ
bulabilen bir makine varsayar; HT30 de kuyrukta beklemeyi sıfır alıp üç çalıştırıcının her an
hazır olduğunu kabul etti. İki varsayım da aynı karara bağlıdır: hattın nerede koştuğu. Hat her
koşumda temiz kurulan bir makinede koşarsa önbellek her seferinde boştur ve buradaki 1 819
saniyelik kazanç buharlaşır; kendi tutulan makinelerde koşarsa önbellek kalır, ama makineler
bekler, eskir ve bakım ister. Sonraki ders aynı hattı iki çalıştırıcı türünde koşturup dört kalemi
sayar — kuyrukta bekleme, koşum başına maliyet, önbelleğin kalıcılığı ve bakım yükü — sonra eşiği
hesaplar: günde kaç koşumdan sonra hangisi ucuzluyor.
