Ders 01 / 17
Tek İş Parçacıklı Model
JavaScript'in tek iş parçacıklı, sonuna kadar çalışan yürütme modeli; engelleyen işin sonuçları; dilin çekirdeği ile çalışma zamanının sağladığı eşzamansız yeteneklerin ayrımı.
İçindekiler
Önceki iki kurs dilin değer modelini kurdu: değerler, nesneler, prototip zinciri ve kapanışlar. Bunların tümü tek bir varsayım altında anlatıldı — kod yazıldığı sırada çalışır, bir deyim biter, sonraki başlar. Bu kurs o varsayımı kaldırır.
Bir ölçüm istasyonundan veri istediğinizde yanıt hemen gelmez. Yanıt beklenirken program ne yapar? “Bekler” yanıtı, tek iş parçacıklı bir dilde çok pahalıya mal olur. Bu ders, bekleme kararının neden verilemeyeceğini ve dilin bunun yerine ne yaptığını kurar.
Tek İş Parçacığı Ne Anlama Gelir
Bir iş parçacığı (thread), komutları sırayla yürüten tek bir yürütme akışıdır. Bir JavaScript programında bu akıştan yalnız bir tane vardır: herhangi bir anda kullanıcı kodunun tek bir satırı çalışır. İki fonksiyon aynı anda ilerlemez, iki döngü iç içe geçmez, iki geri çağrı çakışmaz.
Bunun doğrudan bir sonucu vardır: veri yarışı (data race) yoktur. Bir değişkeni okuyup yazdığınız iki satır arasına başka bir kod giremez. Diğer dillerde kilit gerektiren bir sayaç artırımı, burada gerekmez.
İşletim sisteminin süreç ve iş parçacığı kavramları, çekirdek düzeyindeki zamanlama ve gerçek paralellik ayrı bir konudur; İşletim Sistemi Kavramları kursunda ele alınır. Bu kurs, tek bir iş parçacığına düşen kod üzerinde durur.
Sonuna Kadar Çalışma
Modelin ikinci kuralı, tek iş parçacığı kadar bağlayıcıdır: bir kez çalışmaya başlayan bir iş, kendisi bitene kadar bölünmez. Buna sonuna kadar çalışma (run-to-completion) denir.
Bunun anlamı, “sıfır milisaniye sonra çalıştır” diye kaydedilmiş bir işin bile önündeki işin bitmesini beklemesidir.
function toplamHesapla(tur) { let toplam = 0; for (let i = 0; i < tur; i += 1) toplam += i % 7; return toplam; } setTimeout(() => console.log("3 — zamanlayıcı geri çağrısı"), 0); console.log("1 — hesap başlıyor"); const sonuc = toplamHesapla(5_000_000); console.log("2 — hesap bitti, sonuç:", sonuc);
1 — hesap başlıyor 2 — hesap bitti, sonuç: 14999995 3 — zamanlayıcı geri çağrısı
Geri çağrı en başta kaydedildi ve gecikmesi sıfırdı; buna karşın en sonda çalıştı.
setTimeout bir işi şimdi çalıştırmaz, sıraya koyar. Sıradaki iş ancak yürüyen kod
bittikten sonra ele alınır. Bu ilkenin ayrıntısı sonraki derste açılacak.
Sonuna kadar çalışma, tek iş parçacığının doğal eşlikçisidir. Yürüyen bir fonksiyonun ortasında başka bir geri çağrının çalışabildiğini varsayarsanız, kilitlere ve yeniden girilebilirlik (reentrancy) tartışmasına geri dönersiniz. Model, bu karmaşıklığı program yazarından uzak tutmak için basitliği seçer — bedeli, sıradaki her işin öndekini beklemesidir.
Engelleyen İş
Engelleyen (blocking) iş, iş parçacığını başka hiçbir şey yapamayacak biçimde meşgul eden iştir. İki kaynağı vardır.
Birincisi uzun süren hesaplamadır: milyonlarca elemanlı bir dizinin sıralanması, büyük bir metnin ayrıştırılması. Bunlar işi gerçekten yapar, yalnız uzun sürer.
İkincisi ve daha sinsi olanı, eşzamanlı (synchronous) girdi-çıktı çağrılarıdır. Bir dosyayı eşzamanlı okuyan bir çağrı, disk yanıt verene kadar iş parçacığını tutar; oysa bu sürede iş parçacığı hiçbir hesap yapmaz, yalnız bekler.
import { writeFileSync, readFileSync, readFile } from "node:fs"; writeFileSync("olcumler.txt", "A1;21.4\nB2;19.8\nC3;23.1\n"); readFile("olcumler.txt", "utf8", (hata, veri) => { console.log("3 — eşzamansız okuma bitti:", veri.trim().split("\n").length, "satır"); }); const icerik = readFileSync("olcumler.txt", "utf8"); console.log("1 — eşzamanlı okuma bitti:", icerik.trim().split("\n").length, "satır"); console.log("2 — betiğin geri kalanı");
1 — eşzamanlı okuma bitti: 3 satır 2 — betiğin geri kalanı 3 — eşzamansız okuma bitti: 3 satır
İki okuma da aynı dosyayı okur ve aynı sonucu üretir. Ayrıldıkları nokta, bekleme sırasında iş parçacığının kime ait olduğudur. Eşzamanlı olan onu tutar; eşzamansız olan bırakır ve sonucu hazır olduğunda geri çağrıyla haber verir.
Engellemenin görünen sonucu ortama göre değişir. Tarayıcıda arayüz donar: tıklama işlenmez, çizim güncellenmez, kaydırma takılır. Sunucuda ise tek bir isteğin uzun hesabı, o sırada gelen bütün istekleri kuyrukta bekletir. Her iki durumda da nedeni aynıdır: iş parçacığı tek, sıradaki iş de sabırlı.
Dil Nerede Biter, Çalışma Zamanı Nerede Başlar
Dilin çekirdeği eşzamansızlığı tanımlamaz. Standart, sözleri (promise) ve async
fonksiyonları tanımlar; ancak “on milisaniye sonra” veya “dosya okunduğunda” gibi
kavramların hiçbiri dilin sözdiziminde yer almaz.
Bu yetenekleri ana ortam (host environment) sağlar. JavaScript Temelleri kursunda tanıtılan ayrım burada işlevsel hale gelir:
| Katman | Sağladığı şey |
|---|---|
| Dil çekirdeği | Değerler, fonksiyonlar, sözler, async/await, mikro görev kuralı |
| Ana ortam | Zamanlayıcılar, ağ istekleri, dosya erişimi, olaylar, görev kuyruğu, olay döngüsü |
setTimeout bir dil sözcüğü değildir; ana ortamın kullanıma açtığı bir fonksiyondur. Aynı
biçimde ağ isteği başlatan fonksiyon da ana ortama aittir. Bu nedenle aynı JavaScript kodu
farklı ortamlarda farklı yeteneklerle karşılaşır: tarayıcıda belge nesnesi vardır, sunucu
çalışma zamanında dosya sistemi vardır.
Ayrım, sorumluluğu da böler. Beklemeyi dil yapmaz. Zamanlayıcıyı ana ortam kurar, süre dolduğunda geri çağrıyı kuyruğa koyar; iş parçacığı boşaldığında JavaScript o geri çağrıyı çalıştırır. Bekleme sırasında iş parçacığı serbesttir.
Eşzamansızlık Paralellik Değildir
Bu ayrım kursun tamamında geçerlidir ve baştan yerleşmelidir.
Paralellik, iki işin aynı anda yürütülmesidir; birden çok iş parçacığı ister. Eşzamansızlık, bir işin başlatılıp sonucunun sonra alınmasıdır; tek iş parçacığıyla da mümkündür.
Üç ölçüm isteğini “aynı anda” başlattığınızda, bu isteklerin ağ üzerindeki bekleme süreleri gerçekten üst üste biner — çünkü beklemeyi yapan ana ortamdır, JavaScript değil. Ama yanıtları işleyen kodunuz sırayla çalışır: birinci yanıt işlenirken ikincisi kuyrukta bekler. Böylece programınız beklemede paralel, hesapta sıralıdır.
Bunun pratik sonucu şudur: eşzamansızlık, girdi-çıktı ağırlıklı işi hızlandırır; hesap
ağırlıklı işi hızlandırmaz. Milyon elemanlık bir sıralamayı setTimeout içine koymak onu
hızlandırmaz, yalnız başlangıcını erteler. Hesap yükünü gerçekten dağıtmak için ayrı bir
iş parçacığı gerekir; çalışma zamanları bunu ayrı bir yürütme bağlamı olarak sunar ve
bağlamlar arasında yalnız ileti geçişi yapılır — paylaşılan değişken yoktur.
Kursun Örneği: Ölçüm Akışı
Kurs boyunca tek bir somut örnek üzerinde ilerlenecek: birkaç ölçüm istasyonundan sıcaklık değeri toplayan küçük bir program. İstasyonların yanıt gecikmeleri farklıdır; bazıları hata döndürür, bazıları hiç yanıt vermez.
Bu örnek ders ders şu adımlardan geçecek: geri çağrıyla tek ölçüm, sözle zincirlenmiş ölçüm, birleştiricilerle toplu ölçüm, zaman aşımıyla sınırlanmış ölçüm, iptal edilebilir ölçüm ve son olarak sızıntı bırakmayan sürekli ölçüm akışı.
Program boyunca yazdırılan hiçbir şey süre olmayacak; yalnız sıra olacak. Süre makineye ve yüke göre değişir, sıra ise modelin kuralıdır.
Özet
- JavaScript kullanıcı kodu tek bir iş parçacığında yürür; iki kod parçası aynı anda ilerlemez, bu nedenle veri yarışı oluşmaz.
- Sonuna kadar çalışma kuralı gereği, başlayan bir iş bitmeden sıradaki iş ele alınmaz; sıfır gecikmeli bir geri çağrı bile bunu bekler.
- Engelleyen iş, iş parçacığını meşgul ederek bekleyen bütün işleri geciktirir; uzun hesap ve eşzamanlı girdi-çıktı iki kaynağıdır.
- Zamanlayıcı, ağ ve dosya erişimi dilin değil ana ortamın yetenekleridir; dil yalnız sözleri ve mikro görev kuralını tanımlar.
- Eşzamansızlık beklemeleri üst üste bindirir, hesabı paralelleştirmez.
Sonraki Adım
Bu derste geri çağrıların “sıraya girdiği” söylendi ama sıranın nasıl işlediği söylenmedi. Sıradaki her işin eşit olmadığı, bir söz geri çağrısının bir zamanlayıcı geri çağrısından önce çalıştığı da gösterilmedi. Sonraki ders bu düzeneği açar: çağrı yığıtı, görev kuyruğu ve mikro görev kuyruğu ayrımıyla olay döngüsünün tam kuralını kurar ve karışık bir örnekte çıktı sırasını satır satır gerekçelendirir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.