dart中的isolate
isolate可以理解為dart中的線程,但它又不同于線程魏割,準(zhǔn)確的說應(yīng)該叫做協(xié)程撇寞,協(xié)程最大的優(yōu)勢就是它具有極高的執(zhí)行效率,因?yàn)閿y程中子程序的調(diào)用不需要線程的切換正勒,所以對于線程數(shù)量越大的程序來說協(xié)程的優(yōu)勢就越明顯。每個(gè)isolate都有自己獨(dú)立的執(zhí)行線程和事件循環(huán)傻铣,以及內(nèi)存章贞,所以isolate之間不存在鎖競爭的問題,各個(gè)isolate之間通過消息通信非洲。
root isolate
對于每一個(gè)flutter應(yīng)用鸭限,當(dāng)應(yīng)用被啟動時(shí)都會有一個(gè)默認(rèn)的isolate,稱為root isolate两踏。我們自己的代碼默認(rèn)情況下都在這個(gè)isolate中執(zhí)行败京。
消息循環(huán)
類似于iOS的NSRunLoop或者安卓的Looper,每個(gè)isolate內(nèi)部都有一個(gè)消息循環(huán)梦染,它隨著isolate的創(chuàng)建自動開啟赡麦,存在兩個(gè)隊(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í)行的肮疗,一個(gè)任務(wù)執(zhí)行完成后才會執(zhí)行下一個(gè)任務(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í)行第三個(gè)then");
});
}).catchError((e) {
print("future2 執(zhí)行catchError");
}).whenComplete(() {
print("future2 執(zhí)行whenComplete");
});
future1.then((_) {
print("future1 執(zhí)行第二個(gè)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í)行第二個(gè)then
flutter: future2 初始化任務(wù)
flutter: future2 執(zhí)行then
flutter: future2 執(zhí)行whenComplete
flutter: future1 執(zhí)行第三個(gè)then
flutter: future3 初始化
分析
1族吻、通過Future.value()函數(shù)創(chuàng)建的任務(wù)是立即執(zhí)行的帽借,所以就立即執(zhí)行future4 執(zhí)行then和future4 執(zhí)行whenComplete
2、每一個(gè)Future可以通過then()注冊多個(gè)回調(diào)超歌,他們按照注冊的順序依次執(zhí)行砍艾。當(dāng)所有注冊的then()執(zhí)行完畢后接著會回調(diào)whenComplete。(備注:如果是在whenComplete之后注冊的then巍举,那么這個(gè)then的任務(wù)將放在microtask執(zhí)行脆荷,所以這也就是為什么"future1 執(zhí)行第三個(gè)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
任何一個(gè)函數(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í)等價(jià)于如下:
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)用啟動時(shí)會創(chuàng)建一個(gè)默認(rèn)的Root isolate(也可以理解為Main isolate)而账,根據(jù)官方的說法胰坟,如果在Root isolate中做大量的耗時(shí)任務(wù)有可能被系統(tǒng)wathdog強(qiáng)殺,所以對于一些耗時(shí)任務(wù)可以創(chuàng)建一個(gè)新的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é)束啦");
// 兩個(gè)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對象,一個(gè)線程由
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
兩個(gè)isolate之間基于Port實(shí)現(xiàn)的通信基于如下流程:
SendPort
只能通過ReceivePort獲取铛碑,用于Isolate之間的數(shù)據(jù)通信
ReceivePort
通過所在Isolate的函數(shù)內(nèi)通過ReceivePort()創(chuàng)建狠裹。每一個(gè)ReceivePort可以有多個(gè)SendPort與之對應(yīng)