@43 Asynchronous Programming in Dart & Flutter သင်ခန်းစာ

Dart Programming ရဲ့ Isolate ,Event Loop နဲ့ Flutter ရဲ့ thread runner တွေကြောင်းကို လေ့လာသွားမယ်။

Official You Tube Channel

ကျွန်တော်တို့ IntelliJ Idea မှာ ရေးနေတဲ့ Console Dart Program တွေက Single Thread မှာပဲ run နေတာဖြစ်တဲ့အတွက်ကြောင့် ၁ ကြိမ်မှာ အလုပ် ၁ ခုပဲ လုပ်နိုင်မှာဖြစ်ပါတယ်။

ကျတော်တို့အပေါ်က program ကို run လိုက်မယ်ဆိုရင် one,two,three ကို print ပြီးရင် four ကို‌ရောက်ဖို့အတွက် download ဆိုတဲ့ function ပြီးအောင်စောင့်နေရမှာ ဖြစ်တဲ့အတွက်ကြောင့် အချိန်တော်တော်ကြာအောင်ရပ်နေမှဖြစ်ပါတယ်။ တကယ်လို့ app မှာဆိုရင် UI က လေးပြီး freeze ဖြစ်သွားမှာပါ။ ခုပုံစံတိုင်းရေးထားတာကတော့ synchronous ပါ။ Line by Line ပဲသွားပါတယ်။ အဲ့အတွက် ကျတော်တို့ Download လုပ်တာတို့ လို Long running task တွေ run ဖို့အတွက် asynchronous programming ကိုသုံးမှ ကျတော်တို့ app က smooth ဖြစ်မှာပါ။

Dart Programming မှာ Asynchronous Programming ကိုသုံးဖို့ဆိုရင် High Level Api တွေဖြစ်တဲ့ Future တို့ async and await တို့သုံးပြီး အလွယ်တကူသုံးလို့ရပါတယ်။အဲ့ဒါဆို အဲ့ဒီ Api တွေဘယ်လိုအလုပ်လုပ်လဲဆိုတာလေ့လာသွားမယ်။

Android, IOS တို့မှာဆိုရင် Network Operation တို့ တစ်ခြား I/O process တွေလုပ်ဖို့ဆိုရင် Main Thread မှာပေးမလုပ်ပဲ Background Thread ၁ ခု မှာ ပဲ အဲ့ဒီ Long running process တွေကို သွား run ရပါတယ်။ Android & IOS ကော ၂ မျိုုးလုံးက multi thread run လို့ရတဲ့ အတွက်ကြောင့် single thread လေးနဲ့ပဲ သွား run နေမယ်ဆိုရင် device မှာ ပါတဲ့ performance ကို အပြည့် အဝ အသုံးချလို့ရမှာမဟုတ်ပါဘူး။

Dart Programming Language က Single Thread ဖြစ်ပေမယ့် Flutter Framework ကတော့ OS အလိုက် runner thread တွေနဲ့ Multi threaded run နေတာဖြစ်ပါတယ်။ Flutter is single Thread ဆိုရင်တော့ မမှန်ပါဘူး။ Flutter က Mobile Os တွေဖြစ်တဲ့ Android,IOS နဲ့ Fuchsia OS တို့မှာဆိုရင် app ၁ ခုကို run လိုက်ပြီဆိုတာနဲ့ Thread ၄ ခု Default run နေတာဖြစ်ပါတယ်။

Thread 4 ခုကတော့

1.UI Runner

2.GPU Runner

3.IO Runner

4.Platform Runner

Developer ‌ရေးသမျှ code တွေက UI Runner ထဲကိုပဲရောက်သွားမှာဖြစ်ပြီး သက်ဆိုင်ရာ process တွေကို Framework က Manage လုပ်ပေးသွားမှာဖြစ်ပါတယ်။ ဘယ် thread မှာသွား run ဆိုပြီး handle လုပ်ပေးစရာ မလိုပါ။

GPU နဲ့ဆိုင်တဲ့ အလုပ်တွေကို GPU Runner က လုပ်သွားမှာဖြစ်ပြီးတော့(တကယ်အလုပ်လုပ်တာ ကတော့ CPU ပေါ်မှာပဲ execute လုပ်တာပါ) network operation http , database , file တို့ ဆိုရင်တော့ IO Runner ကလုပ်သွားမှာဖြစ်ပါတယ်။ လိုအပ်လာရင်လဲ Thread တွေ developer က ထပ် create ပြီးသုံးလို့ရပါတယ်။

ဘယ် အချိန်မျိုးမှာ isolate ၁ ခု create လုပ်ပြီးသုံးမလဲဆို large json parsing လုပ်တာမျိုးလို cpu intensive ဖြစ်တဲ့ processတွေမှာ သုံးသင့်ပါတယ်။

Isolate

Dart Programming ရဲ့ Thread model ကတော့ C++ တို့ Java တို့နဲ့ အလုပ်လုပ်ပုံ ခြင်းမတူပါဘူး။ Dart Programming Language မှာ Thread အချင်းချင်း memory sahre လုပ်ပြီးသုံးလို့မရပါဘူး။ အဲ့တာကြောင့် Thread ကို Isolate လို့ခေါ်ပါတယ်။

Thread ၁ ခုနဲ့ ၁ခု Communicate လုပ်ချင်ရင် message passing pattern သုံးပြီး send port တို့ receive port တို့နဲ့သွားရပါတယ်။ အဲ့ အတွက်‌ကြောင့် java တို့ c++ တို့မှာလို synchronize တွေဘာတွေတော့ လုပ်ဖို့မလိုတော့ပါဘူး။

Event Loop

Thread တွေအများကြီး နဲ့ Parallel run နေမှ Asynchronous လုပ်လို့ရတာတော့မဟုတ်ပါဘူး။ Single Thread မှာလဲ Asynchronous လုပ်လို့ရပါတယ်။ Event Loop နဲ့ပါ။ Isolate တစ်ခုဆီမှာ event loop ၁ ခု run နေတာဖြစ်ပါတယ်။ Single Thread မှာ Async and Non Blocking ဖြစ်ဖို့ အတွက် event loop က Handle လုပ်ပေးသွားတာပါ။

Isolate (Thread) ၁ ခု ချင်းဆီမှာ Event loop ၁ ခုဆီ run နေပါတယ်

Single Thread မှာ ၁ကြိမ်ကို process ၁ ခုပဲ run နိုင်တာ ဆိုတော့ asynchronous run မယ့် process တွေ ကို event loop ပေါ်တင်ပေးသွားမှာ ဖြစ်ပါတယ်။ Future , Stream တို့ async and await တို့ က event loop ပေါ်မှာ run တာဖြစ်ပါတယ်။

Async လုပ်ဖို့လိုတဲ့ process တွေကို event loop ပေါ်တင်ပေးလိုက်တော့ normal process တွေက ပုံမှန်ပဲ run သွားနိုင်ပါတယ်။
Normal process တွေ အကုန် runပြီးမှ event loop က အလုပ်လုပ်နိုင်မှာ ဖြစ်ပါတယ်။

Event Loop ထဲမှာ Queue ၂ ခု ရှိတယ်။

Queue ဆိုတာ (FIFO) First in First Out ဖြစ်ပြီး Stack က Last in First out ပါ။ ဒီမှာတော့ stack မပါဘူး 😁

1.Microtask Queue

2.Event Queue

Microtask Queue ထဲမှာ Resource ၁ ခု ကို ပိတ်တာ ဖွင့်တာ လိုမျိုး asynchronous လုပ်ဖို့လိုတဲ့ system ရဲ့ internal action တွေလုပ်တယ်

Event Queue ထဲမှာတော့ screen touch လုပ်တာတို့ Network operation တို့ Future တို့ Stream တို့တွေလုပ်တယ်။

Event Loop က Microtask Queue ကို စ run တယ်။ Microtask Queue ထဲက Process တွေကုန်ပြီဆိုမှ Event Queue ကို စ run တယ်။ Queue ဆိုတော့ process တွေက First in First out run သွားတာပဲဖြစ်ပါတယ်။

Microtask Queue ကို run ဖို့ဆိုရင်

scheduleMicrotask(() {}) ဆိုတဲ့ function နဲ့ အလွယ်တကူခေါ်လို့ရပါတယ်။

Event Queue ကို run ဖို့က တော့ future တို့ Stream တို့ က event queue ထဲမှာ run တာဖြစ်ပါတယ်။

အပေါ်က program ကို run မယ်ဆိုရင် normal process တွေ အရင် လုပ်သွားမယ် ။ ပြီးမှ event loop က စပြီး အလုပ်လုပ်မယ်။

Event loop က microtask process တွေကို အရင်ကုန်သွားအောင် run ပြီးမှ event queue ကို သွား run မှာ ဖြစ်ပါတယ်

Output က တော့ အောက်ကပုံအတိုင်းပဲ ရရှိမှာ ဖြစ်ပါတယ်။

Code ​တွေကို copy & paste လုပ်ပြီး run ကြည့်လို့ရပါတယ်

import 'dart:async';
void main() {

  print('Normal Process 1');
  scheduleMicrotask(() => print('microtask queue 1'));
  Future(() => print('Event Queue 1'));

  print('Normal Process 2');
  scheduleMicrotask(() => print('microtask queue 2'));
  Future(() => print('Event Queue 2'));

  print('Normal Process 3');
  scheduleMicrotask(() => print('microtask queue 3'));
  Future(() => print('Event Queue 3'));

}