Sparround

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: TransferableTypedData və 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ırAyrı — yalnız mesaj ötürmə
Race condition riskiVar — async gap-də state dəyişə bilərYoxdur — ortaq state yoxdur
XərciPraktik olaraq sıfırYaradı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 adi try/catch işləyir.
  • `compute(fn, arg)` — Flutter-in eyni ideyanı həyata keçirən köhnə köməkçisidir. Isolate.run çıxandan sonra compute faktiki olaraq onun üzərində qurulub; yeni kodda Isolate.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/SendPort handshake-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 SocketFile 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.run bunu 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