İçeriğe geç
academia.sh

Ders 05 / 18

Mikroçekirdek ve Eklenti Mimarisi

Değişmeyen küçük bir çekirdek ile sayısı önceden bilinmeyen eklentilerin ayrılması: çekirdek dosyasının eklentiler hakkında bildiği ad sayısının dörtten sıfıra inmesi, beşinci eklenti eklendiğinde çekirdekte düzenlenen satır sayısının ölçülmesi, eklentisiz çekirdeğin tek dosyalık kapanışla koşması ve sözleşmeyi bozan bir eklentinin iki düzende kaç isteği durdurduğunun sayılması.

İçindekiler

Bileşen sınırı yeniden kullanım birimini verdi, ama o ölçülerin hepsi yayın zamanındaydı. Açıkta kalan soru şudur: bu birimlerden hangisi program koşarken takılıp çıkarılabilir. Sınır bir yayın kararıdır, takılıp çıkarılabilirlik bir çalışma zamanı kararı; ikisi aynı kümeyi vermez.

Bu ders birimleri iki sınıfa bölen düzeni ele alır: değişmeyen, tek başına koşabilen küçük bir parça ile onun üzerine takılan, sayısı önceden bilinmeyen parçalar. Dört şey ölçülür: küçük parçanın ötekiler hakkında bildiği ad sayısı, yeni bir parçanın düzenlettiği satır sayısı, parçasız çekirdeğin koşup koşmadığı ve bozuk bir parçanın bütünü durdurup durdurmadığı.

Çekirdek, Eklenti ve Sözleşme

Mikroçekirdek (microkernel) düzeni üç şey ilan eder. Birincisi çekirdektir: hiçbir eklenti takılmasa bile bir yanıt üretebilen en küçük çalışan bütün. Linux’a Giriş kursunda geçen çekirdek işletim sisteminin donanımı yöneten parçasıydı; buradaki çekirdek bir kitaplığın en küçük çalışan parçasıdır ve iki kullanım aynı şey değildir. İkincisi eklentidir (plugin): çekirdeğin yeteneğini genişleten, çekirdeğin adını bilmediği birim. Üçüncüsü eklenti sözleşmesidir: eklentinin karşılaması gereken adların bildirimi.

Bu sözleşme yeni bir kavram değil, bir bağlantı noktasıdır; Alan Odaklı Tasarım kursundaki Bağlantı Noktaları ve Bağdaştırıcılar dersinde kurulmuştur. Bileşen sınırı ile bileşen bölme ilkeleri de Tasarım İlkeleri kursundaki Bileşen Uyum İlkeleri ve Bileşen Bağlaşım İlkeleri derslerinde kurulmuştu. Burada anlatılan ilke değil düzen: sözleşme bir çalışma zamanı kaydına bağlandığında hangi sayıların değiştiği. Belirleyici kısıt tek cümledir — çekirdek hiçbir eklentinin adını taşımaz, yalnız sözleşmenin adlarını taşır.

Kitaplığın Eklentili Düzeni

Ücret hesabı iki parçaya bölünüyor. Çekirdek kademe tablosundan tabanı bulur, yuvarlar ve asgari ücreti uygular; tabana eklenen ya da tabandan düşen her kalem bir eklentidir. Dört eklenti aynı sözleşmeyi karşılıyor: ad, okuduğu gönderi alanlarını bildiren alanlar ve kuruş döndüren kalem. Son dosya kitaplığın değil ölçümün parçasıdır.

mkdir -p mikrocekirdek/eklentiler
cat > mikrocekirdek/tarife.mjs <<'EOF'
// mikrocekirdek/tarife.mjs — kademe tablosu: eklenti degil, cekirdegin kurulus girdisi
export const KADEMELER = [
  { ustAgirlik: 1, ucret: 4990 }, { ustAgirlik: 5, ucret: 8490 },
  { ustAgirlik: 15, ucret: 14990 }, { ustAgirlik: 30, ucret: 24990 },
];
EOF
cat > mikrocekirdek/eklentiler/sozlesme-indirimi.mjs <<'EOF'
// mikrocekirdek/eklentiler/sozlesme-indirimi.mjs — sozlesme oranina gore eksi kalem
const ORAN = { yok: 0, standart: 0.05, hacimli: 0.12 };

export const sozlesmeIndirimi = { ad: "sozlesme-indirimi", alanlar: ["sozlesme"],
  kalem: (g, taban) => -Math.round(taban * (ORAN[g.sozlesme] ?? 0)) };
EOF
cat > mikrocekirdek/eklentiler/hacim-farki.mjs <<'EOF'
// mikrocekirdek/eklentiler/hacim-farki.mjs — hacimsel agirligin gercek agirligi astigi kadar
const HACIM_BOLENI = 5000;
const KG_UCRETI = 900;

export const hacimFarki = { ad: "hacim-farki", alanlar: ["agirlik", "hacim"],
  kalem: (g) => Math.round(Math.max(0, g.hacim / HACIM_BOLENI - g.agirlik) * KG_UCRETI) };
EOF
cat > mikrocekirdek/eklentiler/sigorta-ucreti.mjs <<'EOF'
// mikrocekirdek/eklentiler/sigorta-ucreti.mjs — beyan degerinin binde dordu
const SIGORTA_ORANI = 0.004;

export const sigortaUcreti = { ad: "sigorta-ucreti", alanlar: ["beyanDegeri"],
  kalem: (g) => Math.round(g.beyanDegeri * SIGORTA_ORANI) };
EOF
cat > mikrocekirdek/eklentiler/bolge-farki.mjs <<'EOF'
// mikrocekirdek/eklentiler/bolge-farki.mjs — bolgeye gore sabit ek kalem
const FARK = { yakin: 0, orta: 1500, uzak: 4200 };

export const bolgeFarki = { ad: "bolge-farki", alanlar: ["bolge"],
  kalem: (g) => FARK[g.bolge] ?? FARK.uzak };
EOF
cat > ornek-gonderiler.mjs <<'EOF'
// ornek-gonderiler.mjs — butun olcumlerde kullanilan dort gonderi
export const GONDERILER = [
  { agirlik: 3, hacim: 24000, bolge: "orta", beyanDegeri: 150000, sozlesme: "standart" },
  { agirlik: 0.4, hacim: 1200, bolge: "yakin", beyanDegeri: 0, sozlesme: "yok" },
  { agirlik: 12, hacim: 90000, bolge: "uzak", beyanDegeri: 400000, sozlesme: "hacimli" },
  { agirlik: 28, hacim: 60000, bolge: "orta", beyanDegeri: 25000, sozlesme: "yok" },
];
EOF

Karşılaştırma iki çekirdek arasında yapılıyor. Birincisi dört bileşeni adıyla ithal eder ve sırasını kendi içinde sabitler.

// mikrocekirdek/gomulu.mjs — dort bileseni adiyla ithal eden ve sirasini kendi icinde sabitleyen cekirdek
import { sozlesmeIndirimi } from "./eklentiler/sozlesme-indirimi.mjs";
import { hacimFarki } from "./eklentiler/hacim-farki.mjs";
import { sigortaUcreti } from "./eklentiler/sigorta-ucreti.mjs";
import { bolgeFarki } from "./eklentiler/bolge-farki.mjs";

const ASGARI_UCRET = 3990;
const YUVARLAMA_ADIMI = 50;

export const gomuluCekirdek = (kademeler) => ({
  hesapla: (gonderi) => {
    const kademe = kademeler.find((k) => gonderi.agirlik <= k.ustAgirlik);
    if (kademe === undefined) throw new RangeError("agirlik kademesi yok");
    const taban = kademe.ucret;
    const toplam = taban
      + sozlesmeIndirimi.kalem(gonderi, taban)
      + hacimFarki.kalem(gonderi, taban)
      + sigortaUcreti.kalem(gonderi, taban)
      + bolgeFarki.kalem(gonderi, taban);
    const net = Math.round(toplam / YUVARLAMA_ADIMI) * YUVARLAMA_ADIMI;
    return { tutar: Math.max(net, ASGARI_UCRET), uygulanan: 4, dusen: [] };
  },
});

İkincisi eklenti kaydı tutar. Sözleşmeyi karşılamayan eklenti takma anında reddedilir; koşum anında bozan eklenti o istekte düşürülür ve adı raporlanır.

// mikrocekirdek/eklentili.mjs — cekirdek yalniz sozlesme adlarini bilir; hicbir eklenti adi gecmez
const ASGARI_UCRET = 3990;
const YUVARLAMA_ADIMI = 50;

export const SOZLESME = ["ad", "alanlar", "kalem"];

const karsilar = (e) => typeof e?.ad === "string"
  && Array.isArray(e?.alanlar) && typeof e?.kalem === "function";

export const cekirdek = (kademeler) => {
  const kayit = [];
  return {
    tak: (e) => (karsilar(e) ? (kayit.push(e), true) : false),
    takili: () => kayit.map((e) => e.ad),
    hesapla: (gonderi) => {
      const kademe = kademeler.find((k) => gonderi.agirlik <= k.ustAgirlik);
      if (kademe === undefined) throw new RangeError("agirlik kademesi yok");
      const taban = kademe.ucret;
      const dusen = [];
      let toplam = taban;
      for (const e of kayit) {
        let d = null;
        try { if (e.alanlar.every((a) => gonderi[a] !== undefined)) d = e.kalem(gonderi, taban); }
        catch { d = null; }
        if (Number.isFinite(d)) toplam += d; else dusen.push(e.ad);
      }
      const net = Math.round(toplam / YUVARLAMA_ADIMI) * YUVARLAMA_ADIMI;
      return { tutar: Math.max(net, ASGARI_UCRET), uygulanan: kayit.length - dusen.length, dusen };
    },
  };
};

Eklenti adlarının yazılı olduğu tek yer bileşim köküdür.

// mikrocekirdek/kur.mjs — bilesim koku: cekirdegi kurar, eklentileri bildirilmis sirayla takar
import { cekirdek } from "./eklentili.mjs";
import { sozlesmeIndirimi } from "./eklentiler/sozlesme-indirimi.mjs";
import { hacimFarki } from "./eklentiler/hacim-farki.mjs";
import { sigortaUcreti } from "./eklentiler/sigorta-ucreti.mjs";
import { bolgeFarki } from "./eklentiler/bolge-farki.mjs";

export const EKLENTILER = [sozlesmeIndirimi, hacimFarki, sigortaUcreti, bolgeFarki];

export const kur = (kademeler, eklentiler = EKLENTILER) => {
  const c = cekirdek(kademeler);
  const red = eklentiler.filter((e) => c.tak(e) === false).length;
  return { c, red };
};

Çekirdeğin Bildiği Ad Sayısı

Betik üç dosyanın metninde kaç eklenti adının geçtiğini sayar, kapanışlarını çıkarır, eklentisiz çekirdeği koşturur ve iki düzenin aynı tutarı verdiğini sınar.

// cekirdek-olcum.mjs — cekirdek dosyalarinin bildigi eklenti adi, ithal kapanisi ve eklentisiz kosum
import { readFileSync } from "node:fs";
import { dirname, join, normalize } from "node:path";
import { KADEMELER } from "./mikrocekirdek/tarife.mjs";
import { gomuluCekirdek } from "./mikrocekirdek/gomulu.mjs";
import { cekirdek, SOZLESME } from "./mikrocekirdek/eklentili.mjs";
import { EKLENTILER, kur } from "./mikrocekirdek/kur.mjs";
import { GONDERILER } from "./ornek-gonderiler.mjs";

const ADLAR = EKLENTILER.map((e) => e.ad);

const kapanis = (kok, g = new Set()) => {
  if (g.has(kok)) return g;
  g.add(kok);
  const bul = readFileSync(kok, "utf8").matchAll(/^import\s.*?from\s+"(\.[^"]+)"/gm);
  for (const [, y] of bul) kapanis(normalize(join(dirname(kok), y)), g);
  return g;
};

console.log(`eklenti = ${ADLAR.length}, sozlesme adi = ${SOZLESME.length} (${SOZLESME.join(", ")})`);
for (const d of ["gomulu.mjs", "eklentili.mjs", "kur.mjs"]) {
  const metin = readFileSync(`mikrocekirdek/${d}`, "utf8");
  console.log(`  ${d.padEnd(14)} bildigi eklenti adi = ${ADLAR.filter((a) => metin.includes(a)).length}`
    + `  ithal kapanisi = ${kapanis(`mikrocekirdek/${d}`).size} dosya`);
}

const bos = cekirdek(KADEMELER).hesapla(GONDERILER[0]);
console.log(`\neklentisiz cekirdek: takili = 0, tutar = ${bos.tutar}, uygulanan = ${bos.uygulanan}`);
const cift = GONDERILER.map((g) => [gomuluCekirdek(KADEMELER).hesapla(g), kur(KADEMELER).c.hesapla(g)]);
console.log(`dort eklentiyle tutarlar = ${cift.map(([a]) => a.tutar).join(", ")}`
  + `  uygulanan = ${cift[0][1].uygulanan}`);
console.log(`ayrilan sonuc = ${cift.filter(([a, b]) => a.tutar !== b.tutar).length} / ${cift.length}`
  + `, reddedilen eklenti = ${kur(KADEMELER).red}`);
node cekirdek-olcum.mjs
eklenti = 4, sozlesme adi = 3 (ad, alanlar, kalem)
  gomulu.mjs     bildigi eklenti adi = 4  ithal kapanisi = 5 dosya
  eklentili.mjs  bildigi eklenti adi = 0  ithal kapanisi = 1 dosya
  kur.mjs        bildigi eklenti adi = 4  ithal kapanisi = 6 dosya

eklentisiz cekirdek: takili = 0, tutar = 8500, uygulanan = 0
dort eklentiyle tutarlar = 11800, 5000, 24400, 26600  uygulanan = 4
ayrilan sonuc = 0 / 4, reddedilen eklenti = 0

İlk üç satır düzeni ölçüyor. Gömülü çekirdek dört eklenti adı taşıyor ve kapanışı beş dosya: kuralı yüklemek için dört eklentiyi de yüklemek gerekiyor. Eklentili çekirdek sıfır ad taşıyor ve kapanışı bir dosya. Adlar yok olmadı, yer değiştirdi: bileşim kökü dördünü de biliyor ve kapanışı altı dosya. Düzen bilme yükümlülüğünü çekirdekten alıp tek bir kuruluş dosyasına yığıyor.

Son üç satır eklentisiz çekirdeğin koştuğunu gösteriyor: 3 kg’lık gönderi için taban 8.490 kuruş yuvarlanarak 8.500 kuruş çıktı, uygulanan kalem 0. Dört eklentiyle aynı gönderi 11.800 kuruşa çıkıyor ve dört gönderinin dördünde iki düzenin tutarı birebir aynı.

Beşinci Eklentinin Maliyeti

Uzantı maliyeti, yeni bir yetenek eklendiğinde var olan dosyalarda düzenlenen satır sayısıdır. Beşinci eklenti tabanın yüzdesi olarak bir yakıt farkı ekliyor. Blok, ağacın bir kopyasında iki düzene de aynı eklentiyi ekler; yama yol yorumlarını da düzelttiği için sayım ilk satırı atlıyor.

cp -r mikrocekirdek besinci
cat > besinci/eklentiler/yakit-farki.mjs <<'EOF'
// besinci/eklentiler/yakit-farki.mjs — besinci eklenti: tabanin yuzdesi olarak yakit farki
const YAKIT_ORANI = 0.085;

export const yakitFarki = { ad: "yakit-farki", alanlar: ["bolge"],
  kalem: (g, taban) => Math.round(taban * YAKIT_ORANI) };
EOF
python3 - <<'EOF'
from pathlib import Path

ITHAL = 'import { bolgeFarki } from "./eklentiler/bolge-farki.mjs";'
YAKIT = 'import { yakitFarki } from "./eklentiler/yakit-farki.mjs";'
YAMA = {
    "gomulu.mjs": [(ITHAL, f"{ITHAL}\n{YAKIT}"),
                   ("      + bolgeFarki.kalem(gonderi, taban);",
                    "      + bolgeFarki.kalem(gonderi, taban)\n      + yakitFarki.kalem(gonderi, taban);"),
                   ("uygulanan: 4", "uygulanan: 5"), ("dort bileseni", "bes bileseni")],
    "kur.mjs": [(ITHAL, f"{ITHAL}\n{YAKIT}"), ("bolgeFarki];", "bolgeFarki, yakitFarki];")],
}
for yol in sorted(Path("besinci").rglob("*.mjs")):
    metin = yol.read_text().replace("// mikrocekirdek/", "// besinci/")
    for eski, yeni in YAMA.get(yol.name, []):
        metin = metin.replace(eski, yeni)
    yol.write_text(metin)
EOF
for d in gomulu.mjs eklentili.mjs kur.mjs; do
  f=$(diff <(tail -n +2 mikrocekirdek/$d) <(tail -n +2 besinci/$d))
  echo "$d  cikan satir = $(echo "$f" | grep -c '^<')  eklenen satir = $(echo "$f" | grep -c '^>')"
done
echo "eklenen dosya = $(( $(find besinci -name '*.mjs' | wc -l) - $(find mikrocekirdek -name '*.mjs' | wc -l) ))"
cat > besinci-kontrol.mjs <<'EOF'
// besinci-kontrol.mjs — yamali agacta iki duzen ayni tutari uretiyor mu
import { KADEMELER } from "./besinci/tarife.mjs";
import { gomuluCekirdek } from "./besinci/gomulu.mjs";
import { kur } from "./besinci/kur.mjs";
import { GONDERILER } from "./ornek-gonderiler.mjs";
const iki = [gomuluCekirdek(KADEMELER), kur(KADEMELER).c].map((c) => c.hesapla(GONDERILER[0]).tutar);
console.log(`besinci eklentiyle gomulu = ${iki[0]}, eklentili = ${iki[1]}`);
EOF
node besinci-kontrol.mjs
gomulu.mjs  cikan satir = 2  eklenen satir = 4
eklentili.mjs  cikan satir = 0  eklenen satir = 0
kur.mjs  cikan satir = 1  eklenen satir = 2
eklenen dosya = 1
besinci eklentiyle gomulu = 12500, eklentili = 12500

Aynı yetenek iki düzende de bir dosya ekletti ve iki düzen aynı tutarı verdi, ama düzenlenen satırların yeri farklı. Gömülü çekirdekte üç ayrı yer değişti — ithal satırı, toplama terimi ve uygulanan sayısı — 2 satır çıktı, 4 satır girdi. Eklentili çekirdek dosyasında 0 satır değişti; değişen tek dosya bileşim kökü oldu. Ölçü çekirdeğin kapalı olduğunu söylüyor: yeni bir kalem türü çekirdeği yeniden sınamayı ve yayınlamayı gerektirmiyor.

Sözleşmeyi Bozan Eklenti

Takılıp çıkarılabilirliğin ikinci yüzü, takılan şeyin bozuk olabilmesidir. Blok, sigorta eklentisini imzası doğru, davranışı bozuk bir eklentiyle değiştiriyor.

cp -r mikrocekirdek bozuk
cat > bozuk/eklentiler/sigorta-ucreti.mjs <<'EOF'
// bozuk/eklentiler/sigorta-ucreti.mjs — sozlesmeyi kosum aninda bozan eklenti: sayi yerine hata atiyor
export const sigortaUcreti = { ad: "sigorta-ucreti", alanlar: ["beyanDegeri"],
  kalem: () => { throw new TypeError("beyan degeri okunamadi"); } };
EOF
// dayaniklilik.mjs — sozlesmeyi bozan eklentinin iki duzende kac istegi durdurdugunu sayar
import { KADEMELER } from "./mikrocekirdek/tarife.mjs";
import { gomuluCekirdek as saglamGomulu } from "./mikrocekirdek/gomulu.mjs";
import { EKLENTILER, kur as saglamKur } from "./mikrocekirdek/kur.mjs";
import { gomuluCekirdek as bozukGomulu } from "./bozuk/gomulu.mjs";
import { kur as bozukKur } from "./bozuk/kur.mjs";
import { GONDERILER } from "./ornek-gonderiler.mjs";

const DUZENLER = [
  ["gomulu    / saglam", () => saglamGomulu(KADEMELER)],
  ["gomulu    / bozuk ", () => bozukGomulu(KADEMELER)],
  ["eklentili / saglam", () => saglamKur(KADEMELER).c],
  ["eklentili / bozuk ", () => bozukKur(KADEMELER).c],
];

for (const [ad, yap] of DUZENLER) {
  const c = yap();
  let yanit = 0, ilk = "-", dusen = "-", hata = "";
  for (const g of GONDERILER) {
    try {
      const s = c.hesapla(g);
      if (++yanit === 1) { ilk = String(s.tutar); dusen = s.dusen.join(",") || "yok"; }
    } catch (h) { hata = hata || `${h.name}: ${h.message}`; }
  }
  console.log(`${ad}  yanitlanan = ${yanit}/${GONDERILER.length}  ilk tutar = ${ilk.padStart(6)}`
    + `  ${hata === "" ? `dusen = ${dusen}` : hata}`);
}

const kalemsiz = { ad: "yakit-farki", alanlar: ["bolge"] };
const { c, red } = saglamKur(KADEMELER, [...EKLENTILER, kalemsiz]);
console.log(`\nsozlesmeyi takma aninda bozan eklenti: reddedilen = ${red}, takili = ${c.takili().length}`);
console.log(`  takili adlar = ${c.takili().join(", ")}`);
console.log(`  ayni gonderinin tutari = ${c.hesapla(GONDERILER[0]).tutar}`);
node dayaniklilik.mjs
gomulu    / saglam  yanitlanan = 4/4  ilk tutar =  11800  dusen = yok
gomulu    / bozuk   yanitlanan = 0/4  ilk tutar =      -  TypeError: beyan degeri okunamadi
eklentili / saglam  yanitlanan = 4/4  ilk tutar =  11800  dusen = yok
eklentili / bozuk   yanitlanan = 4/4  ilk tutar =  11200  dusen = sigorta-ucreti

sozlesmeyi takma aninda bozan eklenti: reddedilen = 1, takili = 4
  takili adlar = sozlesme-indirimi, hacim-farki, sigorta-ucreti, bolge-farki
  ayni gonderinin tutari = 11800

Aynı bozuk dosya iki düzende iki ayrı sonuç veriyor. Gömülü çekirdekte dört isteğin dördü yanıtsız kaldı: bileşen çağrısı hesabın gövdesinde olduğu için hata bütün hesabı durdurdu. Eklentili çekirdekte dördü de yanıtlandı, bozuk eklenti düşürüldü ve adı raporlandı; tutar 11.200’e indi, yani sigorta kalemi eksik. Bu doğru bir yanıt değil, eksik bir yanıttır ve raporlanması eksikliği görülebilir kılar.

Son üç satır sözleşmenin öteki yüzü. kalem alanı olmayan eklenti takma anında reddedildi: reddedilen 1, takılı 4 ve tutar 11.800’de kaldı. İki savunma noktası var — biri imzayı, öteki dönen değeri sınıyor — ve ikisi de eklenti adını bilmiyor.

Ödünleşimin Sayıları

Kazanç iki kalite niteliğinde ölçüldü. Değiştirilebilirlikte: çekirdeğin bildiği eklenti adı 4’ten 0’a, kapanışı 5 dosyadan 1 dosyaya indi ve beşinci eklenti çekirdekte 0 satır düzenletti. Kullanılabilirlikte: yanıtlanan istek 0/4’ten 4/4’e çıktı.

Bedel üç kalemde yazılıyor. Birincisi yer değiştirmedir: dört ad bileşim kökünde toplandı ve o dosyanın kapanışı 6 dosya oldu, sıra artık yalnız o dosyadan okunur. İkincisi eksik yanıttır: çekirdeğin ayakta kalması sonucun tam olduğu anlamına gelmez. Üçüncüsü sözleşmedir — üç ad her eklentide tekrarlanır ve sözleşme değiştiği gün beş dosya birlikte değişir.

Özet

  • Mikroçekirdek düzeni üç şey ilan eder: eklentisiz koşabilen bir çekirdek, sayısı önceden bilinmeyen eklentiler ve eklentinin karşılaması gereken adları bildiren sözleşme; sözleşme bir bağlantı noktasıdır.
  • Gömülü çekirdek 4 eklenti adı taşıyor ve kapanışı 5 dosya; eklentili çekirdek 0 ad taşıyor ve kapanışı 1 dosya. Adlar kapanışı 6 dosya olan bileşim köküne taşındı.
  • Eklentisiz çekirdek 3 kg’lık gönderi için 8.500 kuruş üretti, dört eklentiyle 11.800 kuruş çıktı ve dört gönderinin dördünde iki düzenin tutarı aynı.
  • Beşinci eklenti iki düzende de 1 dosya ekletti; gömülü çekirdekte 2 satır çıkıp 4 satır girdi, eklentili çekirdek dosyasında 0 satır değişti.
  • Koşum anında sözleşmeyi bozan eklentiyle yanıtlanan istek gömülü düzende 0/4, eklentili düzende 4/4 oldu; takma anında sözleşmeyi karşılamayan eklenti reddedildi.

Sonraki Adım

Bu dersin bütün ölçüleri çekirdeğin ne bildiği üzerineydi. Eklentiler birbirini hiç tanımıyordu, ama hepsi çekirdek tarafından biliniyordu: sıranın ne olduğu, kimin çağrılacağı ve sonucun nasıl toplanacağı tek bir yerde duruyordu. Sonraki ders o tek yeri de kaldırır. Birimler ne birbirini ne kendilerini çağıran bir merkezi tanır; ortak bir bilgi alanına yazar, oradan okur ve buluşmayı alanın kendisi sağlar. Bunun adı kara tahtadır ve üç şey ölçülür: birimlerin birbiri hakkında bildiği ad sayısı, aynı sonuca ulaşmak için yapılan gereksiz iş — kaç birim aynı veriyi okudu, kaç tur boşa döndü — ve aynı girdinin her koşumda aynı çıktıyı verip vermediği.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat