↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 13 — Konu 61: Event Loop Derinlemesine — Microtask Queue vs Event Queue

4 dk okuma #dart
Dizi · 59/64 Dart Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Dart Nedir, Nerede Kullanılır, Neden Flutter Bu Dili Seçti
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Dart SDK, DartPad, Terminal ile Çalıştırma)
  3. Bölüm 1 — Konu 3: İlk Program (`main()`, `print()`, Dosya Yapısı)
  4. Bölüm 1 — Konu 4: Yorum Satırları, Temel Sözdizimi Kuralları
  5. Bölüm 2 — Konu 5: Değişken Tanımlama — `var`, `final`, `const` Farkı
  6. Bölüm 2 — Konu 6: Temel Tipler — `int`, `double`, `String`, `bool`
  7. Bölüm 2 — Konu 7: Tip Çıkarımı (Type Inference) ve Açık Tip Belirtme
  8. Bölüm 2 — Konu 8: `dynamic` ve `Object` — Ne Zaman Kullanılır, Ne Zaman Kaçınılır
  9. Bölüm 2 — Konu 9: Null Safety Temelleri (`?`, `!`, `late`'e Giriş)
  10. Bölüm 3 — Konu 10: Aritmetik, Atama, Karşılaştırma, Mantıksal Operatörler
  11. Bölüm 3 — Konu 11: `if / else if / else`
  12. Bölüm 3 — Konu 12: `switch` / `switch expression` (Modern Dart)
  13. Bölüm 3 — Konu 13: Ternary Operatör, `??`, `??=`, `?.`
  14. Bölüm 3 — Konu 14: `for`, `while`, `do-while` Döngüleri
  15. Bölüm 4 — Konu 16: `List` — Oluşturma, Erişim, Temel Metodlar
  16. Bölüm 4 — Konu 17: `Set` — Benzersiz Eleman Mantığı
  17. Bölüm 4 — Konu 18: `Map` — Key-Value Yapılar
  18. Bölüm 4 — Konu 19: Koleksiyon Üzerinde `for-in`, `forEach`
  19. Bölüm 4 — Konu 20: Spread Operatörü (`...`, `...?`) ve Collection If/For
  20. Bölüm 5 — Konu 21: Fonksiyon Tanımlama, Parametreler (Positional, Named, Optional)
  21. Bölüm 5 — Konu 22: Varsayılan Parametre Değerleri (Derinlemesine)
  22. Bölüm 5 — Konu 23: Arrow Function (`=>`) Sözdizimi
  23. Bölüm 5 — Konu 24: Fonksiyonlar Birinci Sınıf Vatandaş — Değişkene Atama, Parametre Olarak Geçme
  24. Bölüm 5 — Konu 25: Anonim Fonksiyonlar ve Closure Kavramı (Derinlemesine)
  25. Bölüm 5 — Konu 26: Recursion (Özyineleme)
  26. Bölüm 6 — Konu 27: Class Tanımlama, Constructor (Varsayılan, Named, Factory)
  27. Bölüm 6 — Konu 28: Alanlar (Fields), Metodlar, `this` Kullanımı (Derinlemesine)
  28. Bölüm 6 — Konu 29: Initializer List, Constructor Kısayolları (Derinlemesine)
  29. Bölüm 6 — Konu 30: Getter / Setter
  30. Bölüm 6 — Konu 31: Statik Üyeler (`static`)
  31. Bölüm 7 — Konu 32: Kalıtım (`extends`), `super` Kullanımı
  32. Bölüm 7 — Konu 33: Metod Override Etme, `@override`
  33. Bölüm 7 — Konu 34: Soyut Sınıflar (`abstract class`)
  34. Bölüm 7 — Konu 35: Interface Mantığı (`implements`)
  35. Bölüm 7 — Konu 36: Mixin (`with`)
  36. Bölüm 7 — Konu 37: `enum` — Basit ve Gelişmiş (Metotlu Enum'lar)
  37. Bölüm 8 — Konu 38: `try / catch / finally`, `throw`
  38. Bölüm 8 — Konu 39: Özel Exception Sınıfları Yazma
  39. Bölüm 8 — Konu 40: Sound Null Safety Derinlemesine — `late`, `required`, Non-Nullable Varsayılan Davranış
  40. Bölüm 8 — Konu 41: `assert` ile Geliştirme Zamanı Kontrolleri
  41. Bölüm 9 — Konu 42: Generic Sınıflar ve Fonksiyonlar
  42. Bölüm 9 — Konu 43: Generic Sınırlamalar (`<T extends ...>`)
  43. Bölüm 9 — Konu 44: Dart'ın Built-in Generic Koleksiyonları Nasıl Çalışır
  44. Bölüm 10 — Konu 45: `Future` Kavramı, `async`/`await`
  45. Bölüm 10 — Konu 46: `Future.then`, Hata Yönetimi (`catchError`)
  46. Bölüm 10 — Konu 47: `Stream` Temelleri, `async*`, `yield`
  47. Bölüm 10 — Konu 48: `StreamController`, Broadcast Stream
  48. Bölüm 11 — Konu 49: `map`, `where`, `reduce`, `fold`
  49. Bölüm 11 — Konu 50: `sort`, Custom Comparator ile Sıralama
  50. Bölüm 11 — Konu 51: Iterable Kavramı Derinlemesine (Lazy Evaluation)
  51. Bölüm 11 — Konu 52: Cascade Notasyonu (`..`)
  52. Bölüm 12 — Konu 53: `pubspec.yaml`, pub.dev'den Paket Ekleme
  53. Bölüm 12 — Konu 54: Kütüphane Oluşturma, `import`/`export`, `part`/`part of`
  54. Bölüm 12 — Konu 55: Dart'ta Test Yazımı (`test` Paketi, Unit Test Mantığı)
  55. Bölüm 12 — Konu 56: Extension Methods
  56. Bölüm 12 — Konu 57: Dart'ın Derleme Modelleri (JIT vs AOT) ve Bunun Flutter'a Etkisi
  57. Bölüm 13 — Konu 59: Dart 3 Pattern Matching — Records, Destructuring, Sealed Classes, Exhaustive Switch
  58. Bölüm 13 — Konu 60: `Never` Tipi, `covariant` ve Generic Variance Detayları
  59. Bölüm 13 — Konu 61: Event Loop Derinlemesine — Microtask Queue vs Event Queue
  60. Bölüm 13 — Konu 62: Memory Model & Performans — Garbage Collection, `const` Nesnelerin Bellek Avantajı
  61. Bölüm 13 — Konu 63: Isolate'ler Arası Mesajlaşmanın Maliyeti ve `compute()`'un İç İşleyişi
  62. Bölüm 13 — Konu 64: FFI (Foreign Function Interface) — C Koduna Erişim
  63. Bölüm 13 — Konu 65: Sunucu Tarafında Dart — `dart:io`, `shelf` Paketiyle Basit Bir Backend/CLI Aracı Yazma
  64. Bölüm 13 — Konu 66: Derleyici & Analiz Araçları — `dart analyze`, Custom Lint Kuralları, `build_runner` Mimarisi
Dizinin sayfası →
İçindekiler 9 başlık
  1. Tek İş Parçacığı, Ama Nasıl "Eşzamanlı" Görünüyor?
  2. İki Kuyruk: Microtask Queue ve Event Queue
  3. await Aslında Ne Yapıyor?
  4. Bir Future Zincirinde Hata Yayılımı — Tam Mekanik
  5. Yakalanmayan Bir Hata — Ne Olur?
  6. Future.then() Zincirinde Hata Yayılımı
  7. Neden Bu Mekaniği Bilmek Önemli? — Pratik Sonuçlar
  8. 🎯 Bu Dersten Çıkarılması Gerekenler
  9. 📝 Ödevler

Bölüm 10'da Future/async/await'i kullanmayı öğrenmiştik. Bu derste, bunların arka planda tam olarak nasıl çalıştığını — Dart'ın "event loop" mekanizmasını — işleyeceğiz.

Tek İş Parçacığı, Ama Nasıl "Eşzamanlı" Görünüyor?

Bölüm 12'de Dart'ın tek isolate'te (tek iş parçacığında) çalıştığını öğrenmiştik. Peki, tek bir iş parçacığı varsa, Future'lar nasıl "aynı anda" birden fazla işi yönetiyormuş gibi görünüyor? Cevap: event loop (olay döngüsü) mekanizması.

Zihinsel model: Dart'ın çalışma zamanı, sürekli dönen bir döngüdür — bu döngü, sırayla şunları kontrol eder: "yapılacak bir iş var mı? Varsa yap. Yoksa bekle." Future'lar, bu döngüye "ileride yapılacak işler" olarak eklenir.

İki Kuyruk: Microtask Queue ve Event Queue

Dart'ın event loop'u, iki ayrı kuyruk (queue) kullanır:

  1. Microtask Queue: Küçük, dahili işler için (genelde Future sonuçlarının işlenmesi).
  2. Event Queue: Daha "büyük" dış olaylar için (I/O tamamlanması, zamanlayıcılar — Timer, kullanıcı girdileri).

Kritik kural: Microtask queue, event queue'dan HER ZAMAN önce boşaltılır.

dart
void main() {
  print('1. Senkron kod');

  Future(() => print('4. Event queue (Future ile eklendi)'));

  Future.microtask(() => print('3. Microtask queue'));

  print('2. Senkron kod (devam)');
}

Çıktı:

metin
1. Senkron kod
2. Senkron kod (devam)
3. Microtask queue
4. Event queue (Future ile eklendi)

Bunu adım adım açıklayalım:

  1. Program, önce tüm senkron kodu çalıştırır (1. ve 2. satırları) — event loop, senkron kod çalışırken hiçbir şeye dokunmaz.
  2. Senkron kod bittiğinde, event loop önce microtask queue'yu tamamen boşaltır (3.).
  3. Microtask queue tamamen boşaldıktan sonra, event queue'dan bir sonraki işi alır (4.).

await Aslında Ne Yapıyor?

Bölüm 10'da await'in "Future'ı bekler" dediğimizi hatırlarsan, şimdi bunun tam mekaniğini görelim:

dart
void main() async {
  print('1');
  await Future(() => print('bu bir future'));
  print('3'); // bu satır, future TAMAMLANDIKTAN sonra çalışır
}

await ile karşılaşıldığında, Dart şunu yapar: fonksiyonun geri kalanını (o satırdan sonraki her şeyi), bir microtask olarak "kaydeder" ve o Future tamamlanana kadar bu fonksiyonun çalışmasını duraklatır — ama bu, programın tamamının durması anlamına gelmez! Diğer senkron kod (varsa) ve diğer bekleyen işler, bu sırada çalışmaya devam edebilir.

Bir Future Zincirinde Hata Yayılımı — Tam Mekanik

Bölüm 8'de try/catch'i, Bölüm 10'da bunun asenkron kodla birlikte kullanımını öğrenmiştik. Şimdi bir hatanın, bir Future zincirinde tam olarak nasıl "yayıldığını" görelim:

dart
Future<int> adim1() async {
  print("Adım 1 çalışıyor");
  throw Exception("Adım 1'de hata!");
}

Future<int> adim2() async {
  print("Adım 2 çalışıyor"); // Bu satır HİÇ çalışmaz
  return 42;
}

void main() async {
  try {
    int sonuc1 = await adim1(); // hata burada fırlatılır
    int sonuc2 = await adim2(); // BU SATIRA HİÇ ULAŞILMAZ
    print("Sonuç: $sonuc2");
  } catch (e) {
    print("Hata yakalandı: $e");
  }
}

Çıktı:

metin
Adım 1 çalışıyor
Hata yakalandı: Exception: Adım 1'de hata!

Mekanik olarak ne oluyor? adim1() içindeki throw, o Future'ı "hata durumunda tamamlanmış" (completed with error) olarak işaretler. await adim1() satırı, bu hatayı yakalar ve o anda fırlatır — tıpkı senkron bir throw gibi davranır. Bu, try/catch bloğunun onu doğal olarak yakalamasını sağlar. adim2()'ye hiç ulaşılmaz çünkü Dart, await satırında hata görür görmez, o try bloğunun geri kalanını atlayıp doğrudan catch'e geçer — tıpkı Bölüm 8'de öğrendiğimiz senkron throw davranışı gibi.

Yakalanmayan Bir Hata — Ne Olur?

dart
Future<int> riskliIslem() async {
  throw Exception("Yakalanmayan hata");
}

void main() async {
  int sonuc = await riskliIslem(); // try/catch YOK!
  print(sonuc); // bu satıra hiç ulaşılmaz
}

Bu durumda, hata yakalanmadan üst katmanlara "yayılmaya" devam eder — eğer main()'in kendisi de bunu yakalamıyorsa, program bir "Unhandled exception" hatasıyla çöker. Bu, Bölüm 8'de öğrendiğimiz "hata, en yakın uygun try/catch'e kadar yukarı doğru yayılır" prensibinin, asenkron Future zincirlerinde de birebir aynı şekilde işlediğini gösteriyor.

Future.then() Zincirinde Hata Yayılımı

Bölüm 10 Konu 46'da öğrendiğimiz .then() zincirlerinde de aynı mantık geçerlidir:

dart
void main() {
  Future(() => throw Exception("Hata!"))
      .then((veri) => print("Bu ÇALIŞMAZ: $veri"))
      .then((veri) => print("Bu da ÇALIŞMAZ"))
      .catchError((hata) => print("Yakalandı: $hata"));
}

Bir .then() zincirinde hata oluştuğunda, zincirdeki sonraki tüm .then() blokları atlanır ve kontrol doğrudan en yakın .catchError()'a (veya zincirde bir .then()'in onError parametresine) geçer — tıpkı try/catch'te olduğu gibi.

Neden Bu Mekaniği Bilmek Önemli? — Pratik Sonuçlar

1. Debugging (hata ayıklama) kolaylaşır: Bir asenkron kod parçası beklenmedik sırada çalışıyorsa (örneğin bir print'in "olması gerekenden" önce/sonra çıktığını görüyorsan), microtask/event queue mantığını bilmek, neden böyle olduğunu anlamana yardımcı olur.

2. Performans sorunlarını anlama: Çok sayıda microtask, event queue'nun (kullanıcı etkileşimleri, zamanlayıcılar gibi) gecikmesine yol açabilir — çünkü microtask queue tamamen boşalana kadar event queue'ya sıra gelmez. Bu, Flutter'da UI'ın "tepkisiz" görünmesine yol açabilecek senaryoları anlamak için önemlidir.

3. Hata yönetimi tasarımı: Bir Future zincirinde nereye try/catch veya .catchError() koyman gerektiğine karar verirken, hatanın tam olarak nasıl yayılacağını bilmek, doğru yerde yakalamanı sağlar.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Dart'ın event loop'u, senkron kodu önce çalıştırır, sonra microtask queue'yu tamamen boşaltır, sonra event queue'dan bir iş alır — bu sıra kesindir.
  • await, fonksiyonun geri kalanını bir microtask olarak zamanlar ve o Future tamamlanana kadar (programın tamamını değil, sadece o fonksiyonu) duraklatır.
  • Bir Future zincirinde (async/await veya .then ile) oluşan hata, senkron throw gibi davranır — en yakın try/catch veya .catchError()'a kadar sonraki adımları atlayarak yayılır.
  • Yakalanmayan bir asenkron hata, programın "Unhandled exception" ile çökmesine yol açar.
  • Bu mekaniği bilmek, asenkron kodun çalışma sırasını tahmin etmeni, performans sorunlarını anlamanı ve hata yönetimini doğru tasarlamanı sağlar.

📝 Ödevler

  • [ ] Future ve Future.microtask ile senkron print çağrılarını karışık sırada yazıp, çalıştırmadan önce çıktı sırasını tahmin et; sonra çalıştırıp doğrula.
  • [ ] await kullanan iki adımlı bir asenkron fonksiyonda, ilk adımda throw ile hata fırlat, ikinci adımın hiç çalışmadığını print ile kanıtla.
  • [ ] .then() zincirinde bir hata oluştur, zincirdeki sonraki .then() bloklarının atlandığını, .catchError()'ın çalıştığını göster.
  • [ ] Yakalanmayan bir asenkron hata örneği yaz (try/catch olmadan), "Unhandled exception" davranışını gözlemle.
  • [ ] Kendi cümlelerinle, "microtask queue neden her zaman event queue'dan önce boşaltılır" sorusunu, bu dersten öğrendiklerinle açıkla.

Sıradaki konu: Bölüm 13 — Konu 62: Memory Model & Performans — Garbage Collection, const Nesnelerin Bellek Avantajı