Ders 27 / 30
Özel Kaynak Tanımları
Kurgu bir kaynak türü tanımlanır ve üç şema sürümüyle doğrulanır; geçersiz bildirimlerin kaç tanesinin kabul anında yakalandığı, kaçının koşumda patladığı ve kaçının sessizce yanlış sonuç ürettiği sayılır. Şema büyüdükçe yakalanan hata ile yazım yükünün birlikte artışı ve eski bildirimlerin yeni şemada kaç alanda kırıldığı ölçülür.
İçindekiler
Bir önceki ders şablonun var olan nesne türlerinden yeni birleşimler ürettiğini, ama yeni bir tür üretemediğini ölçtü. Bölgesel ölçüm ağının okuma toplama düzeni de beş nesnenin hiçbirine tam oturmuyor: bir sürüm nesnesi, bir kota ve bir zamanlanmış iş birlikte tek bir kavramı anlatıyor ve o kavramın adı hiçbir yerde yazılı değil.
Kaynak türü tanımı, kümenin tanıdığı nesne türleri listesine yeni bir tür eklemektir. Devredilen karar açıktır: bir bildirimin geçerli olup olmadığına artık gözden geçiren insan değil, kabul anında koşan bir şema doğrulayıcı karar verir. Bu dersin ölçtüğü şey o devrin karşılığıdır — şema büyüdükçe hangi hata sınıfı kabulde yakalanmaya başlıyor, karşılığında kaç alan yazmak gerekiyor, ve eski bildirimler yeni şemada ne kadar kırılıyor.
Ölçüm yine bölgesel ölçüm ağı üzerindedir ve kurgudur. Gerçek küme koşturulmaz; tanımlanan
tür, şema doğrulayıcı ve hattın koşumu node ile kurulmuş bir modeldir.
OI37. Kurgu kaynak türü okuma hattıdır ve on bir alanı vardır. OI38. On iki bildirim önceden yazılıdır; dokuzunda bir kusur bulunur, kusurlar rastgele seçilmemiştir. OI39. Koşum modeli günde 1200 okuma işler ve sonucu üç sınıfa ayırır: doğru, patladı, sessizce yanlış. OI40. Üç şema sürümü vardır: A yalnız varlık, B varlık ile tür ve sıralı küme, C bunlara aralık ve bağımlılık kuralı ekler. OI41. Yazım yükü, zorunlu alan sayısının bildirim sayısıyla çarpımıdır. OI42. Sürüm uyumu ölçümünde eski bildirimler yalnız şema A alanlarını taşır.
Kurgu Bir Kaynak Türü ve Üç Şema
// tur.mjs — kurgu kaynak turu "okuma hatti": alanlar, uc sema surumu, on iki bildirim. export const ALAN = ["ad", "kaynak", "hedef", "toplu-boyut", "pencere-dk", "bicim", "es-zamanli-isci", "yeniden-deneme", "geri-cekilme-sn", "gecikme-siniri-sn", "gunluk-tavan"]; const S = (...a) => a; export const BILDIRIM = [ // ad kaynak hedef toplu pnc bicim isci deneme geri gecikme tavan S("bati-gece", "sayac-kuyrugu", "dogrulayici", 500, 15, "ikili", 4, 3, 2, 960, 2000000), S("dogu-gece", "sayac-kuyrugu", "dogrulayici", 500, 15, "ikili", 4, 3, 2, 960, 2000000), S("merkez-saatlik","sayac-kuyrugu", "faturalama", 250, 60, "metin", 2, 1, 5, 3700, 2000000), S("bati-saatlik", "sayac-kuyrugu", null, 250, 60, "metin", 2, 1, 5, 3700, 2000000), S("dogu-saatlik", null, "faturalama", 250, 60, "metin", 2, 1, 5, 3700, 2000000), S("kuzey-gece", "sayac-kuyrugu", "dogrulayici", "besyuz", 15, "ikili", 4, 3, 2, 960, 2000000), S("guney-gece", "sayac-kuyrugu", "dogrulayici", 500, 15, "ham", 4, 3, 2, 960, 2000000), S("bati-yedek", "sayac-kuyrugu", "dogrulayici", 500, 15, "ikili", "-", 3, 2, 960, 2000000), S("dogu-yedek", "sayac-kuyrugu", "dogrulayici", 500, 0, "ikili", 4, 3, 2, 960, 2000000), S("merkez-yedek", "sayac-kuyrugu", "faturalama", 250, 60, "metin", 2, 5, null, 3700, 2000000), S("bati-hizli", "sayac-kuyrugu", "is-emri", 500, 15, "ikili", 4, 3, 2, 60, 2000000), S("dogu-kisitli", "sayac-kuyrugu", "is-emri", 500, 15, "ikili", 4, 3, 2, 960, 1000), ].map((d) => Object.fromEntries(ALAN.map((a, i) => [a, d[i]]))); const SAYI = { "toplu-boyut": "sayi", "pencere-dk": "sayi", "es-zamanli-isci": "sayi" }; const SAYI2 = { ...SAYI, "yeniden-deneme": "sayi", "geri-cekilme-sn": "sayi", "gecikme-siniri-sn": "sayi", "gunluk-tavan": "sayi" }; export const SEMA = { A: { zorunlu: ALAN.slice(0, 3), tur: {}, kume: {}, aralik: {}, kural: [] }, B: { zorunlu: ALAN.slice(0, 7), tur: SAYI, kume: { bicim: ["ikili", "metin", "sikistirilmis"] }, aralik: {}, kural: [] }, C: { zorunlu: ALAN.filter((a) => a !== "geri-cekilme-sn"), tur: SAYI2, kume: { bicim: ["ikili", "metin", "sikistirilmis"] }, aralik: { "pencere-dk": [1, 1440], "toplu-boyut": [1, 100000], "es-zamanli-isci": [1, 64], "yeniden-deneme": [0, 10] }, kural: [ { ad: "geri cekilme bagimliligi", f: (b) => b["yeniden-deneme"] > 0 && b["geri-cekilme-sn"] == null }, { ad: "gecikme siniri pencereden kucuk", f: (b) => b["gecikme-siniri-sn"] < b["pencere-dk"] * 60 }, { ad: "gunluk tavan gunluk hacimden kucuk", f: (b) => b["gunluk-tavan"] < b["toplu-boyut"] * (1440 / b["pencere-dk"]) } ] }, };
Tür tanımı iki parçadır: alan listesi ve şema. Alan listesi türün ne söyleyebildiğini belirler; şema, söylenenin ne zaman kabul edileceğini. Üç sürüm aynı on bir alan üzerinde farklı sıkılıkta durur — A yalnız alanın var olup olmadığına, B ayrıca türüne ve sıralı küme üyeliğine, C bunlara sayı aralığına ve alanlar arası bağımlılığa bakar.
Kabul Anı ve Koşum
// dogrula.mjs — sema dogrulayici (kabul ani) ve okuma hattinin kurgu kosum modeli. export function dogrula(b, s) { const h = []; for (const a of s.zorunlu) if (b[a] == null) h.push(`${a} eksik`); for (const [a, t] of Object.entries(s.tur)) if (b[a] != null && t === "sayi" && typeof b[a] !== "number") h.push(`${a} sayi degil`); for (const [a, k] of Object.entries(s.kume)) if (b[a] != null && !k.includes(b[a])) h.push(`${a} kume disi`); for (const [a, [alt, ust]] of Object.entries(s.aralik)) if (typeof b[a] === "number" && (b[a] < alt || b[a] > ust)) h.push(`${a} aralik disi`); for (const k of s.kural) if (k.f(b)) h.push(k.ad); return h; } export function kos(b) { // kurgu okuma akisi: gunde 1200 okuma const TOPLAM = 1200; if (!b.kaynak || !b.hedef) throw new Error("kaynak ya da hedef cozulemedi"); if (!["ikili", "metin", "sikistirilmis"].includes(b.bicim)) throw new Error("bilinmeyen bicim"); const pencere = 1440 / b["pencere-dk"]; if (!Number.isFinite(pencere)) throw new Error("pencere sayisi hesaplanamadi"); if (b["yeniden-deneme"] > 0 && b["geri-cekilme-sn"] == null) throw new Error("geri cekilme tanimsiz, yeniden deneme donguye girdi"); const parti = Math.ceil(TOPLAM / b["toplu-boyut"]); const islenen = Number.isFinite(parti) ? Math.min(TOPLAM, b["gunluk-tavan"]) : 0; const gecikme = b["pencere-dk"] * 60 + (parti * 2) / b["es-zamanli-isci"]; const asim = !(gecikme <= b["gecikme-siniri-sn"]); return { islenen, dusen: TOPLAM - islenen, gecikme, asim, dogru: islenen === TOPLAM && Number.isFinite(gecikme) && !asim }; }
// olc.mjs — uc sema surumunde kabulde yakalanan, kosumda patlayan ve sessizce yanlis olan sayilir. import { BILDIRIM, SEMA } from "./tur.mjs"; import { dogrula, kos } from "./dogrula.mjs"; const kosum = BILDIRIM.map((b) => { // sema uygulanmadan gercek kosum sonucu try { return kos(b).dogru ? "dogru" : "sessiz"; } catch { return "patladi"; } }); console.log("sema yokken on iki bildirimin kosumu: " + ["dogru", "patladi", "sessiz"].map((t) => `${t} ${kosum.filter((x) => x === t).length}`).join(" ")); BILDIRIM.forEach((b, i) => { if (kosum[i] === "dogru") return; let n = "hata vermedi, sonuc yanlis"; try { kos(b); } catch (e) { n = e.message; } console.log(` ${b.ad.padEnd(15)} ${kosum[i].padEnd(8)} ${n}`); }); const kisit = (s) => s.zorunlu.length + Object.keys(s.tur).length + Object.keys(s.kume).length + Object.keys(s.aralik).length + s.kural.length; console.log("\nsurum zorunlu alan sema kisiti yazim yuku kabulde kosumda sessizce gecen"); for (const [ad, s] of Object.entries(SEMA)) { const red = BILDIRIM.map((b) => dogrula(b, s).length > 0); const k = kosum.filter((_, i) => !red[i]); const say = (t) => String(k.filter((x) => x === t).length).padStart(2); console.log(` ${ad} ${String(s.zorunlu.length).padStart(2)} ${String(kisit(s)).padStart(2)}` + ` ${String(s.zorunlu.length * BILDIRIM.length).padStart(3)} ${String(red.filter(Boolean).length).padStart(2)}` + ` ${say("patladi")} ${say("sessiz")} ${say("dogru")}`); }
sema yokken on iki bildirimin kosumu: dogru 3 patladi 5 sessiz 4 bati-saatlik patladi kaynak ya da hedef cozulemedi dogu-saatlik patladi kaynak ya da hedef cozulemedi kuzey-gece sessiz hata vermedi, sonuc yanlis guney-gece patladi bilinmeyen bicim bati-yedek sessiz hata vermedi, sonuc yanlis dogu-yedek patladi pencere sayisi hesaplanamadi merkez-yedek patladi geri cekilme tanimsiz, yeniden deneme donguye girdi bati-hizli sessiz hata vermedi, sonuc yanlis dogu-kisitli sessiz hata vermedi, sonuc yanlis surum zorunlu alan sema kisiti yazim yuku kabulde kosumda sessizce gecen A 3 3 36 2 3 4 3 B 7 11 84 5 2 2 3 C 10 25 120 9 0 0 3
İlk blok şemasız durumu verir: on iki bildirimin üçü doğru çalışır, beşi koşumda patlar, dördü hata vermeden yanlış sonuç üretir. Dört sessiz durumun ayrı ayrı nedenleri vardır ve hiçbiri bir kütükte görünmez: parti boyutu metin yazıldığı için sıfır okuma işlenir, işçi sayısı metin olduğu için gecikme hesaplanamaz, gecikme sınırı pencereden küçük olduğu için sınır her turda aşılır, günlük tavan hacimden küçük olduğu için iki yüz okuma düşer. Dördü de “hattı kurdum, çalışıyor” cümlesiyle uyumludur.
Tablo şema büyüdükçe bu dağılımın nasıl kaydığını gösterir. Şema A yalnız iki bildirimi kabulde reddeder; kalan yedi kusur koşuma iner. Şema B beşe çıkar, ama iki sessiz kusur yine geçer. Şema C dokuzunun dokuzunu kabulde yakalar ve koşumda hiçbir kusur kalmaz. Karşılığı da aynı satırda durur: yazım yükü otuz altıdan yüz yirmi alana çıkar, şema tanımındaki kısıt sayısı üçten yirmi beşe çıkar. Kabulde yakalanan her yeni hata sınıfı, on iki bildirimin tümüne yazılan yeni bir alan ya da yeni bir kuraldır.
Aradaki bağın yönü de okunur: A’dan B’ye geçerken üç hata daha yakalanır ve yazım yükü kırk sekiz alan artar — hata başına on altı alan. B’den C’ye geçerken dört hata daha yakalanır ve yük otuz altı alan artar — hata başına dokuz alan. Ucuzlayan şey alan sayısı değil, yakalanan kusurun türüdür: C’nin eklediği üç bağımlılık kuralı tek tek alanlara bakmaz, alanlar arasındaki tutarlılığa bakar ve sessiz kusurların ikisini oradan alır.
Sürüm Uyumu
// uyum.mjs — sema A doneminde yazilmis bildirimler sema C'ye tasinir: kirilan alan ve varsayilanin bedeli. import { ALAN, BILDIRIM, SEMA } from "./tur.mjs"; import { dogrula, kos } from "./dogrula.mjs"; const A_ALAN = SEMA.A.zorunlu, YENI = ALAN.filter((a) => !A_ALAN.includes(a)); const eski = BILDIRIM.map((b) => Object.fromEntries(A_ALAN.map((a) => [a, b[a]]))); const VARSAYILAN = { "toplu-boyut": 500, "pencere-dk": 15, bicim: "ikili", "es-zamanli-isci": 4, "yeniden-deneme": 3, "geri-cekilme-sn": 2, "gecikme-siniri-sn": 960, "gunluk-tavan": 2000000 }; const dolu = eski.map((b) => ({ ...VARSAYILAN, ...b })); const kirik = (k) => k.reduce((t, b) => t + dogrula(b, SEMA.C).length, 0); console.log(`eski bildirim ${eski.length}, her biri ${A_ALAN.length} alan;` + ` sema C ${SEMA.C.zorunlu.length} zorunlu alan istiyor (yeni alan ${YENI.length})`); console.log(`kirilan alan ${kirik(eski)} (bildirim basina ${(kirik(eski) / eski.length).toFixed(1)});` + ` varsayilan tanimlaninca ${kirik(dolu)}`); let ayrik = 0, bildirim = 0; // varsayilan yazili degerden kac alanda ayriliyor for (let i = 0; i < eski.length; i++) { const f = YENI.filter((a) => VARSAYILAN[a] !== BILDIRIM[i][a]); if (f.length) { ayrik += f.length; bildirim++; } } console.log(`varsayilan, kayitli degerden ${bildirim}/${eski.length} bildirimde ve ${ayrik} alanda ayriliyor`); const sonuc = (b) => { try { const r = kos(b); return `okuma ${r.islenen}, gecikme ${Math.round(r.gecikme)} sn`; } catch (e) { return `patladi (${e.message.split(",")[0]})`; } }; for (const i of [0, 2, 11]) console.log(` ${eski[i].ad.padEnd(15)} yazili bildirim: ${sonuc(BILDIRIM[i]).padEnd(28)}` + ` varsayilanla: ${sonuc(dolu[i])}`);
eski bildirim 12, her biri 3 alan; sema C 10 zorunlu alan istiyor (yeni alan 8) kirilan alan 86 (bildirim basina 7.2); varsayilan tanimlaninca 2 varsayilan, kayitli degerden 10/12 bildirimde ve 34 alanda ayriliyor bati-gece yazili bildirim: okuma 1200, gecikme 902 sn varsayilanla: okuma 1200, gecikme 902 sn merkez-saatlik yazili bildirim: okuma 1200, gecikme 3605 sn varsayilanla: okuma 1200, gecikme 902 sn dogu-kisitli yazili bildirim: okuma 1000, gecikme 902 sn varsayilanla: okuma 1200, gecikme 902 sn
Türü genişletmenin bedeli burada çıkar. Şema A döneminde yazılmış on iki bildirim üç alan taşır; şema C on zorunlu alan ister. Bildirim başına ortalama 7,2 alan kırılır, toplamda seksen altı. Bu, tür sahibinin değil bildirim sahiplerinin işidir ve tek seferde ödenir.
Varsayılan tanımlamak kırığı seksen altıdan ikiye indirir — kalan iki kırık şema A döneminde de eksik olan alanlardır. Ama varsayılan bedava değildir: on iki bildirimin onunda, toplam otuz dört alanda, varsayılan değer bildirimde yazılı olandan farklıdır. Örnek satırlar farkın niteliğini gösterir. Gece hattı varsayılanla aynı davranır, çünkü varsayılan zaten onun değerlerinden seçilmiştir. Saatlik hat pencere değerini altmıştan on beşe düşürür ve gecikmesi 3605 saniyeden 902 saniyeye iner — hat aynı ada sahip, ama artık başka bir hattır. Kısıtlı hat günlük tavanını kaybeder ve bin okuma yerine bin iki yüz okuma işler; tavanın var olma nedeni bildirimden silinmiştir.
Kırılmanın da varsayılanın da ölçüsü aynı yerden gelir: eski bildirim yeni alanlar hakkında bir şey söylemiyor ve söylemediği şeyi kimse bilmiyor. Kırılma bilinmezliği görünür kılar ve bedelini bildirim sahibine yükler; varsayılan bilinmezliği kapatır ve bedelini sessizce üstlenir.
Devrin Bilançosu
| Ölçü | Şema A | Şema B | Şema C |
|---|---|---|---|
| zorunlu alan | 3 | 7 | 10 |
| şema tanımındaki kısıt | 3 | 11 | 25 |
| on iki bildirimin yazım yükü (alan) | 36 | 84 | 120 |
| kabulde yakalanan bildirim | 2 | 5 | 9 |
| koşumda patlayan | 3 | 2 | 0 |
| sessizce yanlış | 4 | 2 | 0 |
| geçen ve doğru çalışan | 3 | 3 | 3 |
Devredilen karar tek cümledir: bir bildirimin geçerliliğine insan değil şema karar verir. Bunun için sistemin bilmesi gereken kalemler sayılıdır — on bir alanın adı, üçünün türü ya da sıralı kümesi, dördünün aralığı, üç bağımlılık kuralı. Bilginin maliyeti de sayılıdır: her kalem on iki bildirimin tümüne yazılır, ve bildirim sayısı arttıkça yük doğrusal büyür.
Sistemin bilmediği şeyin ne yaptığı da tablodadır. Şema A dünyasında dört bildirim kabul edilir, koşar, sonuç üretir ve sonuç yanlıştır; şema tavanın hacimden küçük olamayacağını bilmediği için iki yüz okumanın düşmesine izin verir. Şema C aynı kuralı öğrendiğinde o dört kusur kabulden geri döner. Öğrenmenin karşılığı yüz yirmi alanlık yazım yüküdür ve bu yük, kusuru olmayan üç bildirime de aynen biner: doğru yazılmış bildirim de yanlış yazılmışla aynı on alanı yazmak zorundadır.
Özet
- Şemasız durumda 12 bildirimin 3’ü doğru çalıştı, 5’i koşumda patladı, 4’ü hata vermeden yanlış sonuç üretti.
- Şema A 9 kusurun 2’sini, şema B 5’ini, şema C 9’unu kabul anında yakaladı; şema C’de koşuma inen kusur 0’a düştü.
- Karşılığı yazım yüküdür: zorunlu alan 3’ten 10’a, on iki bildirimin toplam yükü 36 alandan 120 alana, şema tanımındaki kısıt 3’ten 25’e çıktı.
- A’dan B’ye hata başına 16 alan, B’den C’ye hata başına 9 alan ödendi; ucuzlatan şey alanlar arası tutarlılığa bakan 3 bağımlılık kuralıdır.
- Şema A döneminde yazılmış bildirimler şema C’de bildirim başına 7,2 alanda kırıldı; varsayılan kırığı 86’dan 2’ye indirdi ama 12 bildirimin 10’unda, 34 alanda yazılı değerden ayrıldı.
Sonraki Adım
Şema bildirimin geçerli olduğunu söyler, doğru olduğunu söylemez. Kabul edilmiş bir okuma hattı bildirimi kümede tek başına hiçbir şey yapmaz; onu okuyup gerçek durumu istenen duruma getirecek bir şey gerekir ve bugün o şey nöbetçi bir insandır. Bir sonraki ders bu tür için gerçekten koşan bir denetleyici yazar: istenen durumu okur, gerçek durumu okur, farkı kapatır ve ikinci turda sıfır iş yapar. Elle işletimde bir olayın kaç adımda ve kaç dakikada kapandığı ile denetleyicide kaç turda kapandığı karşılaştırılır; denetleyiciye kodlanmış işletim bilgisi madde madde sayılır ve kodlanmamış olanın üretimde ne yaptığı gösterilir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.