İçeriğe geç
academia.sh

Ders 02 / 26

Yanıt Akışı

Yanıtın parça parça alınmasının ölçülmesi: 320 çağrılık aynı iş yükünde üç kurulum da 23338 giriş ve 4049 çıkış belirteci harcıyor ve 33 çağrıda yarıda kesiliyor, yani akış tek bir belirteci bile değiştirmiyor. Değişen şey bekleme adımıdır: akışsız istemcide ilk görünen şey ortalama 16,03 adımda gelirken akan istemcide 3,29 adımda geliyor. Ama akış tek başına kullanılabilirliği değiştirmiyor; etiket yanıtın sonundayken kullanılabilir adım iki kurulumda da 16,03 ve kesilen 33 yanıttan kurtarılan 0. Etiket yanıtın başına alındığında kullanılabilir adım 4,96'ya, kesilenlerden kurtarılan 31'e, kullanılabilir pay 0,8625'ten 0,9594'e çıkıyor. Kesilen yanıtların ortalama 0,5801'i elimize ulaşmış oluyor ve alan sırası bu payın işe yarayıp yaramadığını belirliyor.

İçindekiler

Önceki ders konuşma durumunu istemciye yerleştirdi ve her gönderim kararının belirteç bedelini yazdı. Her çağrının yanıtı orada tek parça hâlinde geldi: istemci isteği gönderdi, bekledi, ve elinde bütün bir metin buldu. Basılan ilk parça adımı sütunu hiçbir karara girmemişti.

Yanıt aslında tek parça üretilmez. Model çıktıyı adım adım kurar ve arayüz bu parçaları üretildikleri sırada gönderebilir. Bu ders o seçeneği ölçer ve üç soruyu ayırır: akış toplam belirteci değiştirir mi, ilk görünen adımı ne kadar düşürür, ve ağ yanıtı ortasında kestiğinde geriye kullanılabilir ne kalır. Üçüncü soru bu kursun kuralına doğrudan bağlıdır: başarısızlığı yazılmayan çağrı ölçülmemiş sayılır, ve yarım kalan bir yanıt bir başarısızlıktır.

  • AK9. Kod bir benzeticidir; gerçek bir uç nokta çağrılmaz. Görüşmeler kurgudur, tohum 20260218. Benzetici önceki derste kurulan ağ katmanını taşır.
  • AK10. Yanıt bir parça listesidir. Benzetici parca alanını da döndürür; akan istemci bu listeyi geldiği sırayla birleştirir, akışsız istemci ise ancak tamamlandığında görür.
  • AK11. Ağ kesmesi istemin içeriğine bağlıdır, alan sırasına değil. Üç kurulum aynı istemleri gönderdiği için aynı çağrılar kesilir; karşılaştırma aynı ağ koşulunda yapılır.
  • AK12. Alan sırası bir istek alanıdır, isteme yazılan bir cümle değil. Böylece giriş belirteci üç kurulumda birebir aynı kalır ve yalnız sıra değişir.
  • AK13. İki ayrı bekleme ölçülür: ilk görünen adım (kullanıcının ekranda bir şey gördüğü an) ve kullanılabilir adım (istemcinin etiketi okuyup iş başlatabildiği an).
  • AK14. Kullanılabilirlik ölçütü etiketin okunabilmesidir. Akışsız istemcide yarıda kesilen yanıtın gövdesi hiç elde olmaz; akan istemcide gelen parçalar elde kalır.
  • AK15. Gönderim kararı önceki dersten devralınır ve üç kurulumda da aynıdır: yalnız kullanıcı sıraları. İş yükü kırk görüşmenin sekiz turu, toplam 320 çağrıdır.
  • AK16. Gecikme ham süre olarak değil adım olarak yazılır; gecikme sınıfı yine zincirdir.

Parça Parça Gelen Yanıt

Akan bir istemcinin yaptığı iş iki satırdır: gelen parçayı biriktir, ve biriken metnin karar verilebilir hâle gelip gelmediğine bak. Aşağıdaki akan_istemci bunu yapar ve etiketi ilk okuduğu adımı yazar. butun_istemci ise yanıtın tamamlanmasını bekler; tamamlanmazsa elinde hiçbir şey kalmaz.

# BENZETICI -- KURGUDUR. Gercek bir uc nokta cagrilmaz; ag katmani da benzeticide.
TOHUM, M32 = 20260218, 0xFFFFFFFF
PENCERE, EN_UZUN, HIZ = 240, 24, 37


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


def parcala(m):
    """KURGU belirtecleyici; parca en cok bes damga."""
    b = []
    for s in m.lower().replace(",", " , ").split():
        yeni = True
        while len(s) > 5:
            b.append((s[:5], yeni))
            s, yeni = s[5:], False
        b.append((s, yeni))
    return b


def belirtecle(m):
    return [p for p, _ in parcala(m)]


def birlestir(pl):
    s = ""
    for p, yeni in pl:
        s += (" " if yeni and s else "") + p
    return s


def izno(m):
    h = 2166136261
    for c in m:
        h = ((h ^ ord(c)) * 16777619) & M32
    return h


def cekilis(istem, tohum, tuz):
    return uretec((tohum + tuz) ^ izno(istem))()


KONU = ["fatura", "ariza", "sayac", "tarife", "kesinti"]
KAVRAM = KONU + ["odeme", "sikayet", "bilgi", "genel"]
IZ = {"fatur": "fatura", "tutar": "fatura", "ayrin": "fatura", "borc": "fatura",
      "ariza": "ariza", "bozuk": "ariza", "calis": "ariza", "akmiy": "ariza",
      "sayac": "sayac", "endek": "sayac", "okuma": "sayac", "rande": "sayac",
      "tarif": "tarife", "birim": "tarife", "abone": "tarife", "basam": "tarife",
      "kesin": "kesinti", "duyur": "kesinti", "mahal": "kesinti",
      "odeme": "odeme", "sikay": "sikayet", "bilgi": "bilgi"}
TUZAK = {"degis": "tarife", "kayit": "ariza", "ekip": "kesinti", "takip": "tarife"}
GOVDE = "talebiniz incelendi ve ilgili ekibe iletildi"
SAYAC = [0]


def duzlestir(mesajlar):
    return " ".join(f"{r} : {i}" for r, i in mesajlar)


def cagir(mesajlar, tohum=TOHUM, sicaklik=0.6, en_uzun=EN_UZUN, yer="tek"):
    """yer bir istek alanidir: etiket yanitin basinda mi sonunda mi uretilsin."""
    SAYAC[0] += 1
    istem = duzlestir(mesajlar)
    bel = belirtecle(istem)
    ilk = 1 + len(bel) // 40                      # ilk parcaya kadar gecen adim
    bos = {"giris": len(bel), "cikis": 0, "parca": [], "ilk": ilk}
    if len(bel) > PENCERE:
        return dict(bos, durum="baglam_asimi")
    if SAYAC[0] % HIZ == 0:
        return dict(bos, durum="hiz_siniri")
    r = uretec(tohum ^ izno(istem))
    if len(bel) > 90 and r() < 0.04:
        return dict(bos, durum="zaman_asimi")
    aday = [k for k in KAVRAM if k[:5] in bel]
    if len(aday) < 3:
        aday = list(KAVRAM)
    p = {k: 0.15 for k in aday}
    for t in bel:
        for tablo, w in ((IZ, 1.0), (TUZAK, 0.6)):
            if tablo.get(t) in p:
                p[tablo[t]] += w
    ad = sorted(p)
    if sicaklik <= 0.0:
        k = max(ad, key=lambda a: p[a])
    else:
        from math import exp
        e = [exp(p[a] / sicaklik) for a in ad]
        k = ad[ayrik(r(), [x / sum(e) for x in e])]
    if yer == "basta":
        metin = f"konu {k} , {GOVDE}"
    elif yer == "sonda":
        metin = f"{GOVDE} , konu {k}"
    else:
        metin = k
    pl, durum = parcala(metin), "tamam"
    if len(pl) > en_uzun:
        pl, durum = pl[:en_uzun], "durduruldu"
    u = cekilis(istem, tohum, 91)                 # ag yaniti yarida keser
    if len(pl) > 3 and u < 0.08:
        pl, durum = pl[:1 + int(u / 0.08 * (len(pl) - 1))], "kesildi"
    return {"durum": durum, "giris": len(bel), "cikis": len(pl),
            "parca": pl, "ilk": ilk}


def oku(y):
    return next((s for s in y.split() if s in KONU), None)


def butun_istemci(s):
    """Yanit tamamlanmazsa govde hic elde olmaz."""
    if s["durum"] != "tamam":
        return "", None
    metin = birlestir(s["parca"])
    return metin, (s["ilk"] + s["cikis"]) if oku(metin) else None


def akan_istemci(s):
    """Parcalar geldikce baglanir; etiket okunur okunmaz adim yazilir."""
    metin, kullanilabilir = "", None
    for i, (p, yeni) in enumerate(s["parca"], 1):
        metin += (" " if yeni and metin else "") + p
        if kullanilabilir is None and oku(metin):
            kullanilabilir = s["ilk"] + i
    return metin, kullanilabilir


ACILIS = ["merhaba yardim gerekiyor", "iyi gunler destek istiyorum",
          "selam bir sorunum var", "merhaba destek almak istiyorum"]
ANAHTAR = {"fatura": ["bu ayki fatura tutari gecen aya gore cok yuksek geldi",
                      "faturami odedim ama sistemde borc gorunuyor",
                      "fatura ayrintisini nereden gorebilirim"],
           "ariza": ["evde su akmiyor bir ariza var galiba",
                     "baglanti bozuk oldu ve hic calismiyor",
                     "ariza kaydi actim ama ekip gelmedi"],
           "sayac": ["sayac okumasi yanlis girilmis endeks tutmuyor",
                     "sayac degisimi icin randevu istiyorum",
                     "sayac uzerindeki endeks ile fatura ayni degil"],
           "tarife": ["hangi tarife basamagindayim ogrenmek istiyorum",
                      "tarife degisikligi icin ne yapmam gerekiyor",
                      "birim ucret abone tipine gore degisiyor mu"],
           "kesinti": ["mahallede kesinti var ne zaman gelecek",
                       "planli kesinti duyurusu nereden takip edilir",
                       "aksamdan beri kesinti yasiyoruz"]}
DOLGU = ["tesekkur ederim not aldim", "peki bunun icin ne kadar beklemem gerekir",
         "daha once de ayni durum olmustu", "yazili bir bildirim alabilir miyim",
         "bu konuda kayit acildi mi", "degisiklik yapilirsa haber verilir mi",
         "ekip ne zaman gelir", "hafta sonu da ulasabilir miyim"]
SISTEM = ("sistem", "destek yardimcisisin . etiket kumesi : fatura , ariza , "
                    "sayac , tarife , kesinti .")
SORU = "gorusme {n} icin konu etiketi ver"

GORUSME = []
for i in range(40):                               # 40 KURGU gorusme, sekizer tur
    r = uretec(TOHUM + 7 * i)
    k = KONU[ayrik(r(), [0.24, 0.22, 0.18, 0.20, 0.16])]
    anahtar = ANAHTAR[k][int(r() * 3)]
    yeri = 1 + int(r() * 5)
    tur = [ACILIS[int(r() * 4)]]
    for t in range(1, 7):
        tur.append(anahtar if t == yeri else DOLGU[int(r() * 8)])
    tur.append(SORU.format(n=7301 + i))
    GORUSME.append({"no": 7301 + i, "konu": k, "yeri": yeri + 1, "tur": tur})

g = GORUSME[0]
mesaj = [SISTEM] + [("kullanici", m) for m in g["tur"]]
print(f"gorusme {g['no']} , konu {g['konu']} , giris"
      f" {cagir(mesaj)['giris']} belirtec")
for yer in ("sonda", "basta"):
    s = cagir(mesaj, yer=yer)
    metin, ka = akan_istemci(s)
    print(f"  etiket {yer:<5} cikis {s['cikis']:>2}  ilk parca adimi {s['ilk']}"
          f"  akan istemcide kullanilabilir adim {ka}"
          f"  butun yanit adimi {butun_istemci(s)[1]}")
    print(f"                yanit : {metin}")
print("  ayni istek tohum 20260219 ile ->",
      birlestir(cagir(mesaj, TOHUM + 1, yer="basta")["parca"]))
gorusme 7301 , konu kesinti , giris 113 belirtec
  etiket sonda cikis 14  ilk parca adimi 3  akan istemcide kullanilabilir adim 17  butun yanit adimi 17
                yanit : talebiniz incelendi ve ilgili ekibe iletildi , konu kesinti
  etiket basta cikis 14  ilk parca adimi 3  akan istemcide kullanilabilir adim 6  butun yanit adimi 17
                yanit : konu kesinti , talebiniz incelendi ve ilgili ekibe iletildi
  ayni istek tohum 20260219 ile -> konu kesinti , talebiniz incelendi ve ilgili ekibe iletildi

Aynı görüşme, aynı istem ve aynı çıkış uzunluğu: iki kurulumda da yanıt 14 parça. Değişen tek şey etiketin nerede durduğudur. Etiket sonda olduğunda akan istemci de bütün istemci de 17. adımda karar verebiliyor; akış hiçbir şey kazandırmıyor. Etiket başa alındığında akan istemci 6. adımda kararı veriyor, bütün istemci ise yine 17. adımı bekliyor. Aradaki on bir adım, yanıtın gövdesini okumadan atılabilecek bir beklemedir.

Son satır kursun üçüncü kuralının gereğidir: aynı istek ikinci bir tohumla yine aynı etiketi ve aynı sırayı verdi.

Üç Kurulumun Bekleme ve Kullanılabilirlik Tablosu

Üç kurulum aynı 320 çağrıda koşturulur. İlki akışsızdır ve etiketi sonda ister; ikincisi aynı isteği akıtarak okur; üçüncüsü akıtır ve etiketi başta ister. Çağrılar birebir aynı olduğu için ağ koşulu da aynıdır.

def olc(yer, akis, tohum=TOHUM):
    """yer: sonda | basta. akis: parcalar geldikce mi okunuyor."""
    SAYAC[0] = 0
    g = c = kesik = kesik_kurtulan = dogru = 0
    gorunen, kullanilir = [], []
    for gr in GORUSME:
        for t in range(1, 9):
            mesaj = [SISTEM] + [("kullanici", m) for m in gr["tur"][:t]]
            s = cagir(mesaj, tohum, yer=yer)
            g, c = g + s["giris"], c + s["cikis"]
            if akis:
                metin, adim = akan_istemci(s)
                if s["parca"]:
                    gorunen.append(s["ilk"] + 1)
            else:
                metin, adim = butun_istemci(s)
                if adim is not None:
                    gorunen.append(adim)
            if s["durum"] == "kesildi":
                kesik += 1
                kesik_kurtulan += adim is not None
            if adim is not None:
                kullanilir.append(adim)
            if t == 8 and oku(metin) == gr["konu"]:
                dogru += 1
    ort = sum(gorunen) / len(gorunen), sum(kullanilir) / len(kullanilir)
    return g, c, kesik, kesik_kurtulan, ort[0], ort[1], len(kullanilir) / 320, dogru / 40


KURULUM = [("akissiz , etiket sonda", "sonda", False),
           ("akis , etiket sonda", "sonda", True),
           ("akis , etiket basta", "basta", True)]
print("kurulum                 giris  cikis  kesik  kurtulan  ilk gorunen"
      "  kullanilabilir  kullanilir pay  isabet A  isabet B")
for ad, yer, akis in KURULUM:
    a, b = olc(yer, akis), olc(yer, akis, TOHUM + 1)
    print(f"{ad:<22} {a[0]:>6} {a[1]:>6} {a[2]:>6} {a[3]:>9}  {a[4]:>11.2f}"
          f"  {a[5]:>14.2f}  {a[6]:>14.4f}  {a[7]:>8.4f}  {b[7]:>8.4f}")

SAYAC[0] = 0
pay = []
for gr in GORUSME:
    for t in range(1, 9):
        s = cagir([SISTEM] + [("kullanici", m) for m in gr["tur"][:t]], yer="basta")
        if s["durum"] == "kesildi":
            pay.append(s["cikis"] / 14)
print(f"\nkesilen {len(pay)} yanitta gelen parca payi : en az {min(pay):.4f} ,"
      f" ortalama {sum(pay) / len(pay):.4f} , en cok {max(pay):.4f}")
kurulum                 giris  cikis  kesik  kurtulan  ilk gorunen  kullanilabilir  kullanilir pay  isabet A  isabet B
akissiz , etiket sonda  23338   4049     33         0        16.03           16.03          0.8625    0.7500    0.6500
akis , etiket sonda     23338   4049     33         0         3.29           16.03          0.8625    0.7500    0.6500
akis , etiket basta     23338   4049     33        31         3.29            4.96          0.9594    0.7750    0.6750

kesilen 33 yanitta gelen parca payi : en az 0.0714 , ortalama 0.5801 , en cok 0.9286

İlk iki sütun bu dersin en önemli sonucudur. Giriş 23338, çıkış 4049 ve kesilen çağrı sayısı 33, üç kurulumda da birebir aynı. Akış tek bir belirteci bile değiştirmiyor; ne maliyeti düşürüyor ne yükseltiyor. Bir maliyet muhasebesi tablosunda akışlı ve akışsız istemci ayırt edilemez.

Değişen şey bekleme sütunudur. Akışsız istemcide ilk görünen şey ortalama 16,03 adımda geliyor, çünkü görünen ilk şey zaten bütün yanıttır. Akan istemcide bu 3,29 adıma düşüyor: yaklaşık beşte bir. Kullanıcının ekranında bir şeyin belirmesi bu kadar erkene çekiliyor ve bunun için hiçbir belirteç ödenmiyor.

Akışın Kazandırmadığı ve Alan Sırasının Kazandırdığı

İkinci satırın kullanılabilir adım değeri 16,03’tür, yani birinci satırla aynı. Akış ekrana bir şey getirdi ama istemciye karar verdirmedi, çünkü kararın dayandığı alan yanıtın en sonundaydı. Aynı satırın kurtulan sütunu da sıfırdır: kesilen 33 yanıtın hiçbiri kullanılabilir kalmadı. Akış tek başına bir dayanıklılık düzeneği değildir.

Üçüncü satır farkı alan sırasıyla açar. Kullanılabilir adım 4,96‘ya iniyor, kesilen 33 yanıttan **31’i** kurtarılıyor ve kullanılabilir pay 0,8625’ten 0,9594’e çıkıyor. Kesilen yanıtlarda gelen parça payı en az 0,0714, ortalama 0,5801, en çok 0,9286: yarıda kesilen bir yanıtın ortalama olarak yarısından fazlası elimize ulaşıyor. O payın işe yarayıp yaramaması tümüyle hangi alanın önce üretildiğine bağlı.

Son iki sütun bir uyarı taşıyor. Etiket isabeti üç kurulumda 0,7500 / 0,7500 / 0,7750; ikinci tohumda 0,6500 / 0,6500 / 0,6750. Alan sırasının isabete kattığı 0,0250, aynı satırın iki koşum farkı ise 0,1000. Bu kazanç ölçülmemiş sayılır ve öyle yazılır. Alan sırasının ölçülen kazancı isabette değil, kullanılabilirlik ve bekleme sütunlarındadır; bunlar da koşumdan koşuma değişmeyen sayılardır.

Özet

  • Akış toplam belirteci değiştirmez: üç kurulum da 23338 giriş, 4049 çıkış harcar ve 33 çağrıda kesilir.
  • Akış ilk görünen adımı 16,03’ten 3,29’a düşürür ve bunun için hiçbir belirteç ödenmez.
  • Akış tek başına kullanılabilirliği değiştirmez: etiket sonda olduğunda kullanılabilir adım iki kurulumda da 16,03 ve kesilen 33 yanıttan kurtarılan 0’dır.
  • Etiket yanıtın başına alındığında kullanılabilir adım 4,96’ya, kurtarılan yanıt 31’e, kullanılabilir pay 0,9594’e çıkar.
  • Kesilen yanıtların ortalama 0,5801’i elimize ulaşır; bu payın işe yarayıp yaramadığını alan sırası belirler.
  • Alan sırasının isabete kattığı 0,0250, iki koşum farkı 0,1000 olduğu için ölçülmemiş sayılır; ölçülen kazanç bekleme ve kullanılabilirlik sütunlarındadır.

Sonraki Adım

İki derste yanıt hep okunacak bir metin oldu. Etiket erken geldiğinde iş erken başlıyordu, ama o işi başlatan hep bir insan ya da basit bir yönlendirme kuralıydı. Yanıt doğrudan bir kod yürütmesini tetikleyecekse ölçüt değişir: biçimin okunabilir olması yetmez, çağrılan şeyin var olması ve verilen değerlerin kabul edilebilir olması da gerekir. Sonraki ders modelin çıktısını yürütülecek bir çağrıya bağlar ve üç sayıyı yan yana basar: kaç yanıt şemaya uygun bir çağrı üretiyor, kaçı var olmayan bir ad uyduruyor, ve doğrulama bunların kaçını yakalıyor.

İ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