Flutter之-dart多線程isolate(二)

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í)行泛粹。引用官方的一張圖片


image.png

先看如下代碼:

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)的通信基于如下流程:


image.png

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市汽烦,隨后出現(xiàn)的幾起案子涛菠,更是在濱河造成了極大的恐慌,老刑警劉巖撇吞,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俗冻,死亡現(xiàn)場離奇詭異,居然都是意外死亡牍颈,警方通過查閱死者的電腦和手機(jī)迄薄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來煮岁,“玉大人讥蔽,你說我怎么就攤上這事涣易。” “怎么了冶伞?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵新症,是天一觀的道長。 經(jīng)常有香客問我响禽,道長徒爹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任芋类,我火速辦了婚禮隆嗅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘侯繁。我一直安慰自己胖喳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布巫击。 她就那樣靜靜地躺著禀晓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坝锰。 梳的紋絲不亂的頭發(fā)上粹懒,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音顷级,去河邊找鬼凫乖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛弓颈,可吹牛的內(nèi)容都是我干的帽芽。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼翔冀,長吁一口氣:“原來是場噩夢啊……” “哼导街!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起纤子,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤搬瑰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后控硼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泽论,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年卡乾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翼悴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡幔妨,死狀恐怖鹦赎,靈堂內(nèi)的尸體忽然破棺而出谍椅,到底是詐尸還是另有隱情,我是刑警寧澤古话,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布毯辅,位于F島的核電站,受9級特大地震影響煞额,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沾谜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一膊毁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧基跑,春花似錦婚温、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至篱竭,卻和暖如春力图,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掺逼。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工吃媒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吕喘。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓赘那,卻偏偏與公主長得像,于是被迫代替她去往敵國和親氯质。 傳聞我的和親對象是個(gè)殘疾皇子募舟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容