Ders 03 / 17
Zamanlayıcılar
Gecikmenin alt sınır oluşu, eşit gecikmeli zamanlayıcıların sırası, yinelemeli çalıştırmada kayma ve üst üste binme, kendi kendini zamanlayan döngü ve iptal.
İçindekiler
Önceki ders, kuyruğa iş koyan çağrıların yalnız kayıt yaptığını gösterdi. En sık
kullanılan kayıt aracı zamanlayıcılardır ve verilen sayı çoğu zaman yanlış okunur:
setTimeout(f, 10) çağrısı, f’nin on milisaniye sonra çalışacağını söylemez.
Bu ders o sayının ne söylediğini, eşit gecikmeli zamanlayıcıların hangi sıraya girdiğini ve yinelemeli çalıştırmanın nerede kaydığını kurar. Ölçüm akışının ilk çalışan parçası da burada, zamanlayıcıya dayalı sahte bir istasyon olarak ortaya çıkacak.
Gecikme Bir Alt Sınırdır
setTimeout(geriCagri, gecikme) çağrısının anlamı şudur: geçen süre gecikme değerine
ulaşmadan geri çağrı kuyruğa alınmaz. Kuyruğa alındıktan sonra ne zaman çalışacağı,
önündeki işlerin ne kadar süreceğine bağlıdır.
Aynı anda kaydedilen zamanlayıcılar, gecikmelerine göre sıraya girer; gecikmeleri eşitse kaydedilme sıralarını korurlar.
setTimeout(() => console.log("4 — 20 ms"), 20); setTimeout(() => console.log("3 — 10 ms"), 10); setTimeout(() => console.log("1 — 0 ms, ilk kayıt"), 0); setTimeout(() => console.log("2 — 0 ms, ikinci kayıt"), 0);
1 — 0 ms, ilk kayıt 2 — 0 ms, ikinci kayıt 3 — 10 ms 4 — 20 ms
Sıfır gecikme “hemen” anlamına gelmez, “en erken fırsatta” anlamına gelir. Ana ortamlar ayrıca bir taban gecikme uygular: HTML standardı, beşten derin iç içe geçmiş zamanlayıcılarda alt sınırı dört milisaniyeye çıkarır; sunucu çalışma zamanlarında da sıfır gecikme genellikle bir milisaniyeye yuvarlanır. Sayı ne olursa olsun, alt sınırdan öteye söz verilmez.
Engelleme Alt Sınırı Aşar
Alt sınırın üst sınırı yoktur. Önceki turdaki iş uzun sürerse, süresi çoktan dolmuş bir zamanlayıcı kuyrukta bekler.
function meshgulBekle(sure) { const bitis = Date.now() + sure; while (Date.now() < bitis) { // İş parçacığını kasten meşgul tutar. } } setTimeout(() => { console.log("1 — 10 ms zamanlayıcısı; 50 ms boyunca iş parçacığını tutuyor"); meshgulBekle(50); console.log("2 — 10 ms zamanlayıcısı bitti"); }, 10); setTimeout(() => console.log("3 — 20 ms zamanlayıcısı"), 20);
1 — 10 ms zamanlayıcısı; 50 ms boyunca iş parçacığını tutuyor 2 — 10 ms zamanlayıcısı bitti 3 — 20 ms zamanlayıcısı
İkinci zamanlayıcının süresi, birinci geri çağrı hâlâ çalışırken doldu. Sonuna kadar çalışma kuralı gereği araya giremedi; birinci iş bitene kadar bekledi. Bu, ölçülen gecikmenin neden istenen gecikmeden büyük olabildiğinin tek nedenidir: iş parçacığı meşgul.
Yinelemeli Çalıştırma ve Üst Üste Binme
setInterval(geriCagri, aralik), geri çağrıyı belirli aralıklarla kuyruğa koyar. Aralık,
geri çağrının bitişinden sonraki değil, kaydedilme anlarındaki sürelerle ölçülür. Geri
çağrı aralıktan uzun sürerse, ardışık çalıştırmalar arasında boşluk kalmaz.
Aşağıdaki iki program yalnız tek satırla ayrılır. Birincisinde geri çağrı kısa:
let tik = 0; const kimlik = setInterval(() => { tik += 1; console.log("aralık tiki", tik); if (tik === 3) clearInterval(kimlik); }, 5); setTimeout(() => console.log("30 ms zamanlayıcısı"), 30);
aralık tiki 1 aralık tiki 2 aralık tiki 3 30 ms zamanlayıcısı
Üç tik beşer milisaniyelik aralıklarla tamamlandı ve otuzuncu milisaniyedeki zamanlayıcı sıraya girdi. İkincisinde ise her tik yirmi milisaniye iş yapıyor:
function meshgulBekle(sure) { const bitis = Date.now() + sure; while (Date.now() < bitis) { // İş parçacığını kasten meşgul tutar. } } let tik = 0; const kimlik = setInterval(() => { tik += 1; console.log("aralık tiki", tik); meshgulBekle(20); if (tik === 3) clearInterval(kimlik); }, 5); setTimeout(() => console.log("30 ms zamanlayıcısı"), 30);
aralık tiki 1 aralık tiki 2 30 ms zamanlayıcısı aralık tiki 3
Sıra değişti. İkinci tik, otuzuncu milisaniye gelmeden başladı ve yirmi milisaniye boyunca iş parçacığını tuttu; zamanlayıcı ancak o iş bittikten sonra çalışabildi. Üçüncü tik ise arkasından, neredeyse ara vermeden geldi.
Bu davranışın iki sonucu vardır. Birincisi, setInterval ile kurulan bir akışta geri
çağrılar arasında dinlenme süresi güvence altında değildir. İkincisi, geri çağrı içinde
eşzamansız iş başlatılıyorsa, önceki çalıştırma bitmeden yenisi başlayabilir ve iki iş
üst üste biner.
Kendi Kendini Zamanlayan Döngü
Her çalıştırma arasında en az bir aralık boşluk isteniyorsa, yineleme setTimeout ile
kurulur: geri çağrı işini bitirdikten sonra bir sonrakini kendisi kaydeder.
Bu kalıp, ölçüm akışının ilk çalışan biçimidir. Sahte istasyonlar, gecikmeleri ve değerleri sabit bir tablodan okunur; böylece program her çalıştırmada aynı çıktıyı verir.
const KAYNAK = { A1: { gecikme: 30, deger: 21.4 }, B2: { gecikme: 10, deger: 19.8 }, C3: { gecikme: 20, deger: 23.1 }, }; function akisBasla(istasyonlar, aralik, gericagri) { let sayac = 0; let kimlik = null; let durduruldu = false; function tur() { const istasyon = istasyonlar[sayac % istasyonlar.length]; sayac += 1; gericagri({ sira: sayac, istasyon, deger: KAYNAK[istasyon].deger }); if (!durduruldu) kimlik = setTimeout(tur, aralik); } kimlik = setTimeout(tur, aralik); return function durdur() { durduruldu = true; clearTimeout(kimlik); }; } const durdur = akisBasla(["A1", "B2", "C3"], 5, (olcum) => { console.log(olcum.sira, olcum.istasyon, olcum.deger); if (olcum.sira === 4) durdur(); });
1 A1 21.4 2 B2 19.8 3 C3 23.1 4 A1 21.4
durduruldu bayrağı gereksiz görünebilir; değildir. durdur işlevi, geri çağrının
içinden çağrılır ve o sırada bir sonraki tur henüz kaydedilmemiştir. Yalnız
clearTimeout çağrılsaydı, çağrı zaten çalışmış bir zamanlayıcıyı iptal eder, hemen
ardından tur yeni bir zamanlayıcı kaydederdi ve akış hiç durmazdı. Kendi kendini
zamanlayan döngülerde iptal, bir durum bayrağıyla birlikte kurulmalıdır.
Bekleyen Zamanlayıcı Programı Ayakta Tutar
Bekleyen bir zamanlayıcı, ana ortam için “yapılacak iş var” demektir. Sunucu çalışma zamanı, bekleyen iş kalmayana kadar kapanmaz.
process.on("exit", () => console.log("3 — çalışma zamanı kapanıyor")); setTimeout(() => console.log("2 — bekleyen zamanlayıcı çalıştı"), 50); console.log("1 — betiğin eşzamanlı kısmı bitti");
1 — betiğin eşzamanlı kısmı bitti 2 — bekleyen zamanlayıcı çalıştı 3 — çalışma zamanı kapanıyor
Aynı program clearTimeout ile iptal edilirse, kapanış hemen gerçekleşir:
process.on("exit", () => console.log("2 — çalışma zamanı kapanıyor")); const kimlik = setTimeout(() => console.log("bu satır hiç çalışmaz"), 50); clearTimeout(kimlik); console.log("1 — betiğin eşzamanlı kısmı bitti");
1 — betiğin eşzamanlı kısmı bitti 2 — çalışma zamanı kapanıyor
Bu gözlem ileride iki yerde işe yarayacak: iptal edilmemiş bir zamanlayıcı hem programın kapanmasını geciktirir hem de geri çağrısının kapattığı bütün değerleri bellekte tutar. İkincisi bellek konusunda ele alınacak sızıntı türlerinden biridir.
Zamanlayıcı Ne Değildir
Üç yaygın yanlış okuma vardır ve üçü de aynı kaynaktan çıkar.
setTimeout(f, 0) “hemen çalıştır” değildir; “yığıt boşalınca çalıştır” demektir. Bu
nedenle uzun bir işi ikiye bölmek için kullanılabilir, ama işi hızlandırmaz.
Zamanlayıcı bir kronometre değildir. Geri çağrı içinde geçen süreyi ölçmek için zamanlayıcı gecikmesine güvenilemez; ölçüm ayrı bir araçla yapılır.
Zamanlayıcı bir eşzamanlılık aracı da değildir. İki geri çağrı asla aynı anda çalışmaz; biri bitmeden diğeri başlamaz. Beklemeler üst üste biner, hesaplar binmez.
Özet
- Zamanlayıcı gecikmesi bir alt sınırdır; üst sınır yoktur ve meşgul iş parçacığı bu sınırı serbestçe aşar.
- Eşit gecikmeli zamanlayıcılar kaydedilme sıralarını korur.
setIntervalçalıştırmalar arasında boşluk güvencesi vermez; uzun süren geri çağrılarda tikler üst üste biner.- Kendi kendini zamanlayan
setTimeoutdöngüsü her tur arasında en az bir aralık bırakır; iptali için durum bayrağı gerekir. - Bekleyen bir zamanlayıcı çalışma zamanını ayakta tutar ve geri çağrısının kapattığı değerleri bellekte tutar.
Sonraki Adım
Zamanlayıcılar geri çağrıyı zamana bağladı; sıradaki adım geri çağrıyı sonuca bağlamak. Sonraki ders, ölçüm kaynağını hata bildirebilen bir geri çağrı arayüzüne dönüştürür; üç istasyonu sırayla ve birlikte okumayı dener; ardından bu yaklaşımın sınırlarını gösterir: iç içe geçme, hata yollarının tekrarı ve geri çağrıyı çağıran tarafa bırakmanın getirdiği belirsizlikler. Sözler bu sınırların yanıtı olarak doğacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.