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

Dart Programming ရဲ့ Isolate ,Event Loop နဲ့ Flutter ရဲ့ thread runner တွေကြောင်းကို လေ့လာသွားမယ်။
ကျွန်တော်တို့ 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 လုပ်ပေးသွားတာပါ။

Single Thread မှာ ၁ကြိမ်ကို process ၁ ခုပဲ run နိုင်တာ ဆိုတော့ asynchronous run မယ့် process တွေ ကို event loop ပေါ်တင်ပေးသွားမှာ ဖြစ်ပါတယ်။ Future , Stream တို့ async and await တို့ က event loop ပေါ်မှာ 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'));
}