Ders 13 / 16
Uzun ve Kısa Yoklama
Gerçek zamanlılığın tur satın alınarak taklit edilmesi: yoklamanın protokole tek bir yeni alan eklememesi, karar başına tur maliyetinin dört yaklaşımda da değişmemesi ve harcanan tur ile tur borcunun toplamının sabit kalması.
İçindekiler
Önceki iki ders bağlantıyı açık tutan iki yol ölçtü. Tünel protokolü değiştiriyor, akış gövdeyi bitirmiyordu; ikisi de sunucunun kendiliğinden konuşabilmesi için bağlantının süresini uzatıyordu. Bu dersin sorusu şudur: hiçbirini yapmadan, protokole tek bir yeni alan bile eklemeden, yalnız daha sık sorarak nereye kadar gidilir?
Yoklama (polling), istemcinin durumu öğrenmek için düzenli aralıklarla istek
göndermesidir. Kısa yoklamada sunucu hemen yanıt verir; verecek yeni bir şeyi yoksa
onu söyler. Uzun yoklamada sunucu yanıtı geciktirir; bir değişiklik olana ya da tutma
süresi dolana kadar isteği elinde tutar. Bu dersin ölçüsü ikisinin karar başına ödettiği
turdur. Bir uyarı: önceki derste geçen yokla denetim çerçevesi (ping) ile buradaki
yoklama (polling) ayrı şeylerdir; biri bağlantının ayakta olduğunu doğrulayan bir çerçeve,
öbürü uygulamanın durumu öğrenmek için attığı turdur.
Aynı İstek, Farklı Zaman
İki yoklama biçimi arasındaki farkın iletide bir karşılığı yoktur.
# kısa yoklama — sunucu hemen yanıtlar
GET /olcum/kuzey HTTP/1.1
Host: istasyon.ornek
If-None-Match: "s-118"
HTTP/1.1 304 Not Modified
ETag: "s-118"
# uzun yoklama — istek satırı ve başlıkları aynı, yanıt geciktirilir
GET /olcum/kuzey HTTP/1.1
Host: istasyon.ornek
If-None-Match: "s-118"
HTTP/1.1 200 OK
ETag: "s-119"
Content-Type: application/json
{"istasyon": "kuzey-yamac", "deger": 5}
İki istek birbirinin aynıdır. Yeni bir yöntem, yeni bir başlık alanı, yeni bir durum kodu yoktur. Koşullu istek alanı da yoklamanın icadı değildir; HTTP’nin kendi alanıdır ve bu kursun HTTP ailesi konusunda kurulmuştur. Farkın tamamı sunucunun ne zaman yazdığıdır ve zaman iletide yazan bir şey değildir.
Yoklamanın sunucuya düşen maliyeti — istek sayısı, boş yanıt oranı, tutulan bağlantı — Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda ölçüldü. Burada bölen olay değil karardır ve ölçülen, aradaki aracının hesabıdır.
Ölçüm
- DG11. Kırk tik boyunca istasyonun durumu izlenir. Bir tikte durumun değişip değişmediği kurgunun kâhinindedir; kırk tikin on ikisinde durum değişir.
- DG12. Bir tur, istemcinin istek gönderip yanıt aldığı bir gidiş–dönüştür. Yanıtın boş olması turu ucuzlatmaz.
- DG13. Kısa yoklama her
aralıktikte bir sorar. Uzun yoklama değişiklik olana kadar tutar;tutmatik dolarsa boş yanıt verir ve istemci yeniden bağlanır. - DG14. Sunucu akışı ile tünel tek bir tur harcar; sonrasında aracının okuyabileceği yeni bir ileti yoktur.
- DG15. Alınamayan her beş karar bir tur borcudur: aracı o alışverişin kararını almak isterse sunucuya dönmek zorundadır.
TOHUM = 20260809 GUVENLI = {"GET", "HEAD"} ETKISIZ = {"GET", "HEAD", "PUT", "DELETE"} YONTEMLER = ["GET", "GET", "GET", "HEAD", "POST", "PUT", "DELETE"] YOLLAR = ["/olcum/kuzey", "/olcum/yamac", "/ozet", "/kayit", "/oturum"] KARARLAR = ("saklanabilir", "paylasilabilir", "taze", "yinelenebilir", "yonlendirilebilir") ACIK = ("yontem", "yol", "konak", "ozel_imi", "dogrulayici") def uretec(tohum: int): d = tohum % 2147483646 + 1 def r(n: int) -> int: nonlocal d d = (d * 48271) % 2147483647 return d % n return r def alisverisler(sayi: int = 40) -> list[dict]: r, liste = uretec(TOHUM), [] for i in range(sayi): yontem, yol = YONTEMLER[r(7)], YOLLAR[r(5)] ozel = yol == "/oturum" or r(5) == 0 degisti = r(3) == 0 liste.append({"no": i + 1, "yontem": yontem, "yol": yol, "ozel": ozel, "degisti": degisti, "ozel_imi": ozel and r(4) != 0, "damga_atladi": degisti and r(6) == 0}) return liste def kahin(a: dict) -> dict: return {"saklanabilir": a["yontem"] in GUVENLI and not a["ozel"], "paylasilabilir": not a["ozel"], "taze": not a["degisti"], "yinelenebilir": a["yontem"] in ETKISIZ, "yonlendirilebilir": True} def ileti(a: dict, gorunur: tuple) -> dict: tam = {"yontem": a["yontem"], "yol": a["yol"], "konak": "istasyon.ornek", "ozel_imi": a["ozel_imi"], "dogrulayici": a["degisti"] and not a["damga_atladi"]} return {k: v for k, v in tam.items() if k in gorunur} def araci(i: dict) -> dict: k = {} if "yontem" in i: k["yinelenebilir"] = i["yontem"] in ETKISIZ if "ozel_imi" in i: k["paylasilabilir"] = not i["ozel_imi"] if "yontem" in i: k["saklanabilir"] = i["yontem"] in GUVENLI and not i["ozel_imi"] if "dogrulayici" in i: k["taze"] = not i["dogrulayici"] if "konak" in i: k["yonlendirilebilir"] = True return k def kisa(aralik: int, liste: list[dict]) -> list[int]: """Her `aralik` tikte bir sorulur; yanıt o tikteki durumu döndürür.""" return list(range(aralik - 1, len(liste), aralik)) def uzun(tutma: int, liste: list[dict]) -> list[int]: """Sunucu değişiklik olana kadar tutar; `tutma` tik dolarsa boş yanıt verir.""" turlar, t = [], 0 while t < len(liste): son = min(t + tutma - 1, len(liste) - 1) for u in range(t, son + 1): if liste[u]["degisti"]: son = u break turlar.append(son) t = son + 1 return turlar def olc(turlar: list[int], gorunur: tuple = ACIK) -> tuple: liste = alisverisler() dogru = yanlis = bayt = 0 alanlar = set() for t in turlar: m = ileti(liste[t], gorunur) verilen, gercek = araci(m), kahin(liste[t]) dogru += sum(verilen[k] == gercek[k] for k in verilen) yanlis += sum(verilen[k] != gercek[k] for k in verilen) bayt += sum(len(k) + len(str(v)) + 4 for k, v in m.items()) alanlar |= set(m) alinan = dogru + yanlis oran = len(turlar) / alinan if alinan else float("nan") return (len(turlar), len(alanlar), alinan, dogru, yanlis, 200 - alinan, oran, bayt) LISTE = alisverisler() print(f"tik {len(LISTE)}, karar kümesi {len(LISTE) * len(KARARLAR)}, " f"değişim {sum(a['degisti'] for a in LISTE)}") print() bicim = "{:<18s} {:>4d} {:>5d} {:>7d} {:>6d} {:>7d} {:>11d} {:>10.3f} {:>6d}" print(f"{'yaklaşım':<18s} {'tur':>4s} {'alan':>5s} {'alınan':>7s} " f"{'doğru':>6s} {'yanlış':>7s} {'alınamayan':>11s} {'tur/karar':>10s} " f"{'bayt':>6s}") YAKLASIMLAR = [("kısa yoklama (1)", kisa(1, LISTE), ACIK), ("kısa yoklama (4)", kisa(4, LISTE), ACIK), ("uzun yoklama (5)", uzun(5, LISTE), ACIK), ("sunucu akışı", [0], ACIK), ("tünel", [0], ())] for ad, turlar, gorunur in YAKLASIMLAR[:-1]: print(bicim.format(ad, *olc(turlar, gorunur))) n, alan, alinan, d, y, e, oran, b = olc([0], gorunur=()) print(f"{'tünel':<18s} {n:4d} {alan:5d} {alinan:7d} {d:6d} {y:7d} {e:11d} " f"{'-':>10s} {b:6d}") print() print(f"{'yaklaşım':<18s} {'harcanan tur':>12s} {'tur borcu':>9s} " f"{'toplam':>6s}") for ad, turlar, gorunur in YAKLASIMLAR: olculen = olc(turlar, gorunur) harcanan, borc = olculen[0], olculen[5] // len(KARARLAR) print(f"{ad:<18s} {harcanan:12d} {borc:9d} {harcanan + borc:6d}")
tik 40, karar kümesi 200, değişim 12 yaklaşım tur alan alınan doğru yanlış alınamayan tur/karar bayt kısa yoklama (1) 40 5 200 195 5 0 0.200 3524 kısa yoklama (4) 10 5 50 49 1 150 0.200 896 uzun yoklama (5) 15 5 75 72 3 125 0.200 1317 sunucu akışı 1 5 5 4 1 195 0.200 87 tünel 1 0 0 0 0 200 - 0 yaklaşım harcanan tur tur borcu toplam kısa yoklama (1) 40 0 40 kısa yoklama (4) 10 30 40 uzun yoklama (5) 15 25 40 sunucu akışı 1 39 40 tünel 1 40 41
İlk satır kursun açık rejiminin ta kendisidir: kırk tur, 195 doğru, 5 yanlış, hiç alınamayan karar yok, 3524 bayt. Aralığı dörde çıkarmak turu ona indirir ve alınan kararı elliye düşürür. Uzun yoklama on iki değişim için on iki tur harcar, üç turu da tutma süresinin dolmasına verir: toplam on beş.
Turun Sabiti
alan sütunu dört HTTP yaklaşımında da beştir. Yoklama protokole hiçbir alan
eklemez — ne kısa biçimi, ne uzun biçimi. Sunucu akışı da eklemez. Ekleyen tek şey
turdur ve turun kaç tane olduğu iletide yazmaz.
tur/karar sütunu bunun doğrudan sonucudur: dört yaklaşımda da 0,200. Bu sayı
1/5’tir ve tesadüf değildir. Okunabilir bir alışveriş beş alan taşır, beş alan beş karar
verir; dolayısıyla bir tur her zaman tam beş karar satın alır. Yoklamanın sıklığını
değiştirmek bu oranı oynatamaz, çünkü oranın payı da paydası da aynı alan kümesinden
gelir.
Buradan kursun ikinci iddiasının üçüncü biçimi çıkar. Alan eklemek karar kazandırmıyordu; alanı gizlemek kararı götürüyordu; şimdi görülüyor ki tur eklemek de karar başına maliyeti değiştirmiyor. Yoklama, gerçek zamanlılığı taklit ederken protokolden hiçbir şey almaz; yalnız aynı işlemi daha çok kez yapar.
Tünel satırı bu tablonun dışındadır ve oran hesaplanamaz: alan sıfır olduğunda bölen de sıfır olur. Bir turun satın aldığı karar sayısı sıfırsa, tur satın almanın anlamı da kalmaz.
Tur Muhasebesi
İkinci tablo aynı kırk alışverişi turun iki türüne böler. Harcanan tur, istemcinin gerçekten attığı gidiş–dönüştür. Tur borcu, aracının alamadığı kararlar için sunucuya dönmek zorunda kalacağı gidiş–dönüştür. Dört HTTP yaklaşımında toplam kırktır ve değişmez.
Bu, kursun ekseninin en yalın biçimidir. Kırk alışverişin kararı bir yerden gelmek zorundadır: ya istemci turu peşin öder ve karar iletide gelir, ya da tur borç yazılır ve karar alınamaz. Kısa yoklama borcu sıfıra indirir, kırk turu peşin öder. Sunucu akışı bir tur öder, otuz dokuz borç bırakır. Aradaki her yaklaşım bu doğrunun üzerinde bir noktadır.
Tünel satırı kırk bir verir. Fazladan bir tur, yükseltme el sıkışmasının kendisidir: bir tur harcanmıştır ve karşılığında hiçbir karar alınmamıştır. Kırk alışverişin kırkı da borç kalır. Gizlemenin bedeli, tablonun tek satır dışına taşan yerinde durur.
Tutulan İsteğin Aracıdaki Karşılığı
Uzun yoklamanın aracı için bir yan etkisi vardır. Sunucu isteği elinde tutarken bağlantı üzerinde hiçbir bayt akmaz; aracının gördüğü şey, yanıtı gecikmiş bir istektir. Aracının elinde bu bekleyişin kasıtlı olduğunu söyleyen hiçbir alan yoktur — istek satırı olağan bir GET’tir, başlıklarda “beni bekleteceksin” diyen bir alan yoktur. Önceki derste geçen boşta bekleme süresi ise bir aracının olağan kuralıdır ve tutulan isteği, bekletildiğini bilmeden keser.
- DG16. Aracı, üzerinde bayt akmayan bir bağlantıyı boşta bekleme süresi eşiğini
aştığında keser; istemci kesilen turu yeniden açar. Tablodaki
boşta kesmesütunu bu eşiği tik cinsinden verir.
TOHUM = 20260809 YOLLAR = ["/olcum/kuzey", "/olcum/yamac", "/ozet", "/kayit", "/oturum"] def uretec(tohum: int): d = tohum % 2147483646 + 1 def r(n: int) -> int: nonlocal d d = (d * 48271) % 2147483647 return d % n return r def degisimler(sayi: int = 40) -> list[bool]: """Önceki bloğun üretecinden yalnız `degisti` imi alınır; çağrı sırası korunur.""" r, liste = uretec(TOHUM), [] for _ in range(sayi): r(7) # yöntem seçimi yol = YOLLAR[r(5)] ozel = yol == "/oturum" or r(5) == 0 degisti = r(3) == 0 if ozel: r(4) # kişiye özel imi if degisti: r(6) # damga çözünürlüğü liste.append(degisti) return liste def uzun_turlar(tutma: int, degisti: list[bool]) -> list[tuple]: """Her tur (başlangıç, bitiş) tik çiftidir; bitiş ya değişim ya tutma sınırıdır.""" turlar, t = [], 0 while t < len(degisti): son = min(t + tutma - 1, len(degisti) - 1) for u in range(t, son + 1): if degisti[u]: son = u break turlar.append((t, son)) t = son + 1 return turlar TURLAR = uzun_turlar(5, degisimler()) SURELER = [s - b + 1 for b, s in TURLAR] print(f"uzun yoklama (tutma 5): {len(TURLAR)} tur, süreler {SURELER}") print() print(f"{'boşta kesme':>11s} {'kesilen tur':>11s} {'toplam tur':>10s} " f"{'alınan karar':>12s} {'tur/karar':>9s}") for esik in (1, 2, 3, 5, 10): kesilen = sum(1 for s in SURELER if s > esik) toplam = len(TURLAR) + kesilen print(f"{esik:11d} {kesilen:11d} {toplam:10d} {toplam * 5:12d} " f"{toplam / (toplam * 5):9.3f}")
uzun yoklama (tutma 5): 15 tur, süreler [2, 5, 5, 3, 5, 1, 1, 2, 1, 3, 4, 4, 1, 1, 2]
boşta kesme kesilen tur toplam tur alınan karar tur/karar
1 10 25 125 0.200
2 7 22 110 0.200
3 5 20 100 0.200
5 0 15 75 0.200
10 0 15 75 0.200
alınan karar sütunu turun beşle çarpımıdır; bir önceki ölçüm okunabilir her alışverişin
tam beş karar verdiğini göstermişti. Bir tiklik bir kesme eşiği on beş turun onunu keser ve
toplamı yirmi beşe çıkarır. Uzun yoklamanın kazandırdığı tur böylece geri alınır: on beş
turla iş görecek bir düzen, aracının eşiği yüzünden yirmi beş tur harcar. Tutma süresini
eşiğin altına çekmek çözer — beş tiklik eşikte hiçbir tur kesilmez — ama bu, uygulamanın
kendi tasarımını yolun üzerindeki bir ayara göre seçmesi demektir.
tur/karar sütunu burada da 0,200’de durur. Kesilen tur da okunabilir bir alışveriştir ve
o da beş karar verir. Kesme, aracının aldığı kararın oranını değiştirmez; yalnız
istemcinin ödediği turu artırır.
Turla Satın Alınan Şey
Turun karar satın almadığı yerde ne satın aldığını da söylemek gerekir: tazelik. Kısa yoklamada aralık bir tik olduğunda istemci her değişimi olduğu tikte öğrenir. Aralık dört tik olduğunda en kötü durumda üç tik geç öğrenir. Uzun yoklama bu gecikmeyi tur harcamadan kapatır — sunucu değişimi beklediği için yanıt tam değişim anında yazılır — ve on beş turla kırk turun tazeliğini verir.
Bu, üç yaklaşımın gerçek ayrımıdır ve karar tablosunda hiç görünmez. Karar tablosu aracının hesabıdır; tazelik istemcinin hesabıdır. Bir protokol seçimi ikisini birden tartar: aracının kaç karar alabildiği ve istemcinin kaç turla ne kadar yeni bilgi aldığı. Ölçüm bandının alt sınırı burada da geçerlidir; iki yüz kararlık bir kümede ölçülebilen en küçük fark 1/200 = 0,0050’dir ve tablodaki farkların hepsi bunun çok üstündedir.
Özet
- Kısa ve uzun yoklamanın istekleri birbirinin aynıdır; fark sunucunun yanıtı ne zaman yazdığındadır ve zaman iletide yazan bir alan değildir.
- Dört HTTP yaklaşımında da aracının okuduğu alan sayısı beştir; yoklama protokole tek bir yeni alan eklemez.
- Karar başına tur maliyeti dört yaklaşımda da 0,200’dür, çünkü okunabilir bir alışveriş her zaman tam beş karar verir; sıklığı değiştirmek bu oranı oynatmaz.
- Harcanan tur ile tur borcunun toplamı dört HTTP yaklaşımında da kırktır: kısa yoklama 40 + 0, uzun yoklama 15 + 25, sunucu akışı 1 + 39.
- Tünel toplamı kırk bire çıkarır; fazladan tur, karşılığında hiçbir karar alınmayan yükseltme el sıkışmasıdır.
- Turun satın aldığı şey karar değil tazeliktir ve tazelik aracının tablosunda hiç görünmez.
Sonraki Adım
Üç yaklaşım da tek bir uygulamanın iki ucu arasındaydı ve hepsi aynı taşıma zarfını kullanıyordu: aynı konak adı, aynı bağlantı, aynı beş alan. Aracının hesabı bu yüzden tek bir sayaçta tutulabildi — hangi turun hangi alışverişe ait olduğu her zaman belliydi. Kimi protokol ise tek bir bağlantı bile kullanmaz. Sonraki ders, iletilerin birden çok bağlantıya dağıldığı bir protokol ailesini ölçer ve şu soruyu sorar: aracı gördüğü turu göremediği bir turla eşleştiremiyorsa, sayacında ne kalır?
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.