Isolate-lar və concurrency
Dart-da paralellik model olaraq thread-lərlə yox, isolate-lərlə qurulub. Isolate — öz yaddaşı, öz event loop-u və öz garbage collector-u olan müstəqil icra vahididir.
Əsas prinsip bir cümlədədir: isolate-lər yaddaşı bölüşmür. Bundan çıxan nəticələr:
- Ortaq dəyişən yoxdur, deməli race condition, mutex, lock və `synchronized` da yoxdur. Bu, Dart-ın concurrency modelinin ən böyük üstünlüyüdür.
- Ünsiyyət yalnız mesaj ötürmə ilə olur:
SendPort(yazmaq üçün) vəReceivePort(oxumaq üçün). - Göndərilən obyektlər dərin surətlə (deep copy) köçürülür — bir tərəfdə dəyişiklik digərinə təsir etmir. İstisna:
TransferableTypedDatavə immutable obyektlər (String, sabitlər) — onlar kopyalanmadan ötürülür.
Müqayisə üçün: async/await eyni isolate daxilində, tək thread-də növbələşdirmədir; isolate isə həqiqətən ayrı CPU nüvəsində işləyə bilər.
| Sual | `async`/`await` | Isolate |
|---|---|---|
| Hansı problemi həll edir? | **Gözləmək** — I/O, şəbəkə, fayl, timer | **Hesablamaq** — CPU-intensiv iş |
| Neçə thread? | Bir — növbələşmə (concurrency) | Ayrı — həqiqi paralellik |
| Yaddaş | Ortaq — bütün obyektlər əlçatandır | Ayrı — yalnız mesaj ötürmə |
| Race condition riski | Var — async gap-də state dəyişə bilər | Yoxdur — ortaq state yoxdur |
| Xərci | Praktik olaraq sıfır | Yaradılma (~ms) + arqument və nəticənin kopyalanması + yaddaş |
| Ləğvetmə | Yoxdur (Future ləğv olunmur) | `isolate.kill()` — real ləğvetmə |
API-lər: hansını seçmək?
- `Isolate.run(fn)` (Dart 2.19+) — müasir və 95% hallarda düzgün seçim. Isolate yaradır,
fn-i icra edir, nəticəni qaytarır və isolate-i bağlayır. Xəta baş verərsə, xəta əsas isolate-də yenidən atılır — yəni aditry/catchişləyir. - `compute(fn, arg)` — Flutter-in eyni ideyanı həyata keçirən köhnə köməkçisidir.
Isolate.runçıxandan sonracomputefaktiki olaraq onun üzərində qurulub; yeni koddaIsolate.runüstündür, çünki Flutter-dən asılı deyil və closure qəbul edir. - `Isolate.spawn(entryPoint, message)` — aşağı səviyyəli API. Isolate uzunömürlü olmalı və onunla davamlı mesajlaşmaq lazımdırsa bunu seçirsən: worker pool, davamlı dekodlaşdırma, oyun məntiqi. Burada
ReceivePort/SendPorthandshake-ini özün qurmalısan.
Nə göndərmək olar, nə olmaz? Göndərilə bilənlər: null, num, bool, String, TypedData, bunlardan ibarət List/Map/Set, SendPort, Capability, və Dart 2.15-dən sonra əksər adi obyektlər (dərin kopyalanır) və hətta top-level/static funksiyalar və closure-lar.
Göndərilə bilməyənlər: ReceivePort özü, açıq Socket və File handle-ları, dart:ffi pointer-ləri və native resursları tutan obyektlər. Flutter-də əlavə olaraq UI-yə bağlı hər şey — BuildContext, Image handle-ı, platform kanalı. Bunları göndərməyə cəhd ArgumentError verir.
Isolate-in dürüst qiyməti. Isolate pulsuz deyil və müsahibədə bunu bilmək fərq yaradır:
- Yaradılma: yeni heap, yeni event loop, runtime-ın hazırlanması — mobil cihazda tipik olaraq bir neçə millisaniyə və ~1-2 MB yaddaş.
Isolate.runbunu hər çağırışda edir. - Kopyalama: arqument və nəticə serializasiya olunur. 10 MB-lıq siyahını isolate-ə göndərib geri almaq özü-özlüyündə bahalıdır — bəzən hesablamanın özündən baha. Ölçmədən qərar vermə.
- Nəticə: qısa işlər üçün isolate ziyandır. 2 ms-lik iş üçün 5 ms yaradılma + 3 ms kopyalama xərcləmək mənasızdır.
Qayda: isolate-i 10-16 ms-dən uzun sürən, təmiz CPU işi üçün seç. Tipik namizədlər: böyük JSON parse/encode, şəkil emalı və resize, kriptoqrafiya və hash, böyük siyahının sıralanması/filtrlənməsi, CSV və ya PDF generasiyası, ML inference.
Tez-tez təkrarlanan iş üçün hər dəfə yeni isolate yaratmaq əvəzinə uzunömürlü worker saxla (Isolate.spawn + port handshake) — yaradılma xərci bir dəfə ödənilir.
Mühüm istisna: şəbəkə sorğusu isolate tələb etmir. O, gözləməkdir, hesablamaq deyil — await kifayətdir. Bu səhv müsahibədə çox olur.
Müsahibə ipucu. Ən çox verilən sual: "isolate ilə async/await fərqi nədir?" Cavabı bir cümlə ilə aç və o cümlə bütün müsahibəni yadda saxlanan edir: "`async` gözləməni həll edir, isolate isə hesablamanı." Sonra izah et: şəbəkə cavabını gözləmək thread tutmur, ona görə await kifayətdir; 10 MB JSON-u parse etmək isə CPU-nu tutur və await ona heç nə etmir — o iş yenə eyni thread-də işləyəcək və UI donacaq.
İkinci hazır cavab: "isolate-lər yaddaşı bölüşməsi nə deməkdir?" — race condition, lock və mutex-in olmaması; ünsiyyətin yalnız kopyalanmış mesajlarla getməsi; və bunun qiyməti — böyük datanın serializasiyası.
Ən çox edilən iki səhv: (1) şəbəkə sorğusunu isolate-də işlətmək istəmək; (2) isolate-in xərcini nəzərə almamaq — kiçik iş üçün isolate performansı pisləşdirir. Cavaba "ölçmədən qərar vermirəm, DevTools-un timeline-ında hansı işin kadr büdcəsini keçdiyinə baxıram" cümləsini əlavə et — bu, praktik təcrübə siqnalıdır.
📚 Mənbələr və sənədlər
- Dart-da concurrencyrəsmidart.dev
- Isolate classrəsmiapi.dart.dev