dart中的isolate
isolate可以理解為dart中的線程,但它又不同于線程,準(zhǔn)確的說應(yīng)該叫做協(xié)程,協(xié)程最大的優(yōu)勢就是它具有極高的執(zhí)行效率,因?yàn)閿y程中子程序的調(diào)用不需要線程的切換,所以對于線程數(shù)量越大的程序來說協(xié)程的優(yōu)勢就越明顯。每個isolate都有自己獨(dú)立的執(zhí)行線程和事件循環(huán),以及內(nèi)存,所以isolate之間不存在鎖競爭的問題,各個isolate之間通過消息通信。
root isolate
對于每一個flutter應(yīng)用,當(dāng)應(yīng)用被啟動時都會有一個默認(rèn)的isolate,稱為root isolate。我們自己的代碼默認(rèn)情況下都在這個isolate中執(zhí)行。
消息循環(huán)
類似于iOS的NSRunLoop或者安卓的Looper,每個isolate內(nèi)部都有一個消息循環(huán),它隨著isolate的創(chuàng)建自動開啟,存在兩個隊(duì)列 event queue和microtask queue,后者優(yōu)先級高于前者,提交到隊(duì)列中的任務(wù)按照順序依次執(zhí)行。引用官方的一張圖片

先看如下代碼:
void function_main() async
{
print("開始執(zhí)行");
Timer.run((){
print("timer event 立即執(zhí)行1");
});
Future.delayed(Duration(seconds:1),(){
print("event 延遲2秒執(zhí)行");
});
scheduleMicrotask((){
print("micro task 立即執(zhí)行1");
});
print("結(jié)束執(zhí)行");
}
執(zhí)行結(jié)果為:
flutter: 開始執(zhí)行
flutter: 結(jié)束執(zhí)行
flutter: micro task 立即執(zhí)行1
flutter: timer event 立即執(zhí)行1
flutter: event 延遲2秒執(zhí)行
符合預(yù)期
接下來看如下一段代碼:
void function_main() async
{
print("開始執(zhí)行");
Timer.run((){
print("timer event 執(zhí)行1");
scheduleMicrotask((){
print("微任務(wù)2");
});
});
scheduleMicrotask((){
print("micro task 執(zhí)行1");
Timer.run(() {
print("time event 執(zhí)行2");
});
});
print("結(jié)束執(zhí)行");
}
運(yùn)行結(jié)果如下:
flutter: 開始執(zhí)行
flutter: 結(jié)束執(zhí)行
flutter: micro task 執(zhí)行1
flutter: timer event 執(zhí)行1
flutter: 微任務(wù)2
flutter: time event 執(zhí)行2
可以看到microtask 優(yōu)先級比event要高,而且提交到隊(duì)列中的任務(wù)是順序執(zhí)行的,一個任務(wù)執(zhí)行完成后才會執(zhí)行下一個任務(wù)
Future
Future用于異步任務(wù),通過它可以創(chuàng)建到event loop和microtask隊(duì)列中的任務(wù)去執(zhí)行,請看如下一段代碼
void function_main() async
{
print("開始執(zhí)行");
Future future1 = new Future(() => null);
future1.then((value){
print("future1 執(zhí)行then2");
});
future1.then((_) {
print("future1 執(zhí)行then");
}).catchError((e) {
print("future1 執(zhí)行catchError");
}).whenComplete(() {
print("future1 執(zhí)行whenComplete");
});
Future future2 = new Future((){
print("future2 初始化任務(wù)");
});
future2.then((_) {
print("future2 執(zhí)行then");
future1.then((_){
print("future1 執(zhí)行第三個then");
});
}).catchError((e) {
print("future2 執(zhí)行catchError");
}).whenComplete(() {
print("future2 執(zhí)行whenComplete");
});
future1.then((_) {
print("future1 執(zhí)行第二個then");
});
Future future3 = Future((){
print("future3 初始化");
});
Future future4 = Future.value("立即執(zhí)行").then((value){
print("future4 執(zhí)行then");
}).whenComplete((){
print("future4 執(zhí)行whenComplete");
});
print("main 結(jié)束");
}
執(zhí)行結(jié)果為:
flutter: 開始執(zhí)行
flutter: main 結(jié)束
flutter: future4 執(zhí)行then
flutter: future4 執(zhí)行whenComplete
flutter: future1 執(zhí)行then2
flutter: future1 執(zhí)行then
flutter: future1 執(zhí)行whenComplete
flutter: future1 執(zhí)行第二個then
flutter: future2 初始化任務(wù)
flutter: future2 執(zhí)行then
flutter: future2 執(zhí)行whenComplete
flutter: future1 執(zhí)行第三個then
flutter: future3 初始化
分析
1、通過Future.value()函數(shù)創(chuàng)建的任務(wù)是立即執(zhí)行的,所以就立即執(zhí)行future4 執(zhí)行then和future4 執(zhí)行whenComplete
2、每一個Future可以通過then()注冊多個回調(diào),他們按照注冊的順序依次執(zhí)行。當(dāng)所有注冊的then()執(zhí)行完畢后接著會回調(diào)whenComplete。(備注:如果是在whenComplete之后注冊的then,那么這個then的任務(wù)將放在microtask執(zhí)行,所以這也就是為什么"future1 執(zhí)行第三個then"在"future3 初始化"前執(zhí)行的原因),參考官方文檔then的注釋
* When this future completes with a value,
* the [onValue] callback will be called with that value.
* If this future is already completed, the callback will not be called
* immediately, but will be scheduled in a later microtask.
3、catchError是then函數(shù)里拋出異常后會被執(zhí)行
async和await
任何一個函數(shù)都可以加上async關(guān)鍵字,它會將函數(shù)的返回值自動轉(zhuǎn)換成Future類型,await關(guān)鍵字只能用于返回值為Future類型的函數(shù)前面,如下代碼:
String _data = "";
int clickCount = 0;
Future<void> _buttonClick() async {
var data = _data + "Started $clickCount: ${DateTime.now().toString()}";
print("開始啦");
await Future.delayed(new Duration(seconds: 2));
data += " End $clickCount: ${DateTime.now().toString()} ";
clickCount += 1;
_data = data;
print("結(jié)束啦 $_data");
}
// ignore: non_constant_identifier_names
void function_main() async
{
for (int i=0;i<5;i++) {
_buttonClick();
}
print("最終值 $_data");
}
最終的輸出結(jié)果為:
flutter: 開始啦
flutter: 開始啦
flutter: 開始啦
flutter: 開始啦
flutter: 開始啦
flutter: 最終值
flutter: 結(jié)束啦 Started 0: 2021-03-08 08:21:18.766893 End 0: 2021-03-08 08:21:20.772541
flutter: 結(jié)束啦 Started 0: 2021-03-08 08:21:18.769211 End 1: 2021-03-08 08:21:20.772872
flutter: 結(jié)束啦 Started 0: 2021-03-08 08:21:18.769887 End 2: 2021-03-08 08:21:20.773108
flutter: 結(jié)束啦 Started 0: 2021-03-08 08:21:18.770458 End 3: 2021-03-08 08:21:20.773354
flutter: 結(jié)束啦 Started 0: 2021-03-08 08:21:18.770836 End 4: 2021-03-08 08:21:20.773580
這里分析一下代碼的執(zhí)行順序,function_main()函數(shù)中連續(xù)調(diào)用_buttonClick()五次,按照之前的分析await之前的語句順序執(zhí)行五次,等待2秒之后,await之后的語句再順序執(zhí)行五次,所以await之后的data變量的值固定為Started 0: 2021-03-08 08:21:18.766893,clickCount由于每次執(zhí)行后會加1,所以它的值會變化。上面函數(shù)其實(shí)等價于如下:
Future<void> _buttonClick() async {
var data = _data + "Started $clickCount: ${DateTime.now().toString()}";
print("開始啦");
return Future.delayed(new Duration(seconds: 2)).then((value) {
data += " End $clickCount: ${DateTime.now().toString()} ";
clickCount += 1;
_data = data;
print("結(jié)束啦 $_data");
});
}
創(chuàng)建新的isolate
當(dāng)flutter應(yīng)用啟動時會創(chuàng)建一個默認(rèn)的Root isolate(也可以理解為Main isolate),根據(jù)官方的說法,如果在Root isolate中做大量的耗時任務(wù)有可能被系統(tǒng)wathdog強(qiáng)殺,所以對于一些耗時任務(wù)可以創(chuàng)建一個新的iso去完成,當(dāng)做完任務(wù)后再通過Port和Main isolate進(jìn)行通信,請看如下代碼:
void function_main() async
{
print("開始啦");
var receivePort = new ReceivePort();
var sp1 = receivePort.sendPort;
var sp2 = receivePort.sendPort;
print("值 ${sp1==sp2}");
await Isolate.spawn(entryPoint, receivePort.sendPort);
print("結(jié)束啦");
// 兩個isolate之間通過SendPort來進(jìn)行通信
SendPort sendPort = await receivePort.first;
print("結(jié)束啦1");
// Send a message to the Isolate
sendPort.send("hello");
print("結(jié)束啦2");
}
entryPoint(SendPort sendPort) async {
// Open the ReceivePort to listen for incoming messages (optional)
print("進(jìn)來啦1");
// 創(chuàng)建跟當(dāng)前線程關(guān)聯(lián)的ReceivePort對象,一個線程由
var port = new ReceivePort();
// Send messages to other Isolates
sendPort.send(port.sendPort);
print("進(jìn)來啦2");
// Listen for messages (optional)
await for (var data in port) {
print("data $data");
}
print("進(jìn)來啦3");
}
打印結(jié)果:
flutter: 開始啦
flutter: 值 true
flutter: 結(jié)束啦
flutter: 進(jìn)來啦1
flutter: 進(jìn)來啦2
flutter: 結(jié)束啦1
flutter: 結(jié)束啦2
flutter: data hello
兩個isolate之間基于Port實(shí)現(xiàn)的通信基于如下流程:

SendPort
只能通過ReceivePort獲取,用于Isolate之間的數(shù)據(jù)通信
ReceivePort
通過所在Isolate的函數(shù)內(nèi)通過ReceivePort()創(chuàng)建。每一個ReceivePort可以有多個SendPort與之對應(yīng)