Flutter開發(fā)進(jìn)階:Flutter事件循環(huán)機(jī)制與異步

Dart是基于 事件循環(huán)機(jī)制的單線程模型, 所以Dart中沒有多線程, 也就沒有主線程與子線程之分。

  • 單線程模型:一條執(zhí)行線上同時(shí)只能執(zhí)行一個(gè)任務(wù),如果有耗時(shí)任務(wù)則需要放入隊(duì)列異步執(zhí)行。
  • 多線程:充分利用處理器的多核優(yōu)勢(shì)進(jìn)行并行計(jì)算。

一、事件循環(huán)機(jī)制

對(duì)于用戶點(diǎn)擊, 滑動(dòng), 硬盤IO訪問等事件, 你不知道何時(shí)發(fā)生或以什么順序發(fā)生, 所以得有一個(gè)永不停歇且不能阻塞的循環(huán)來等待處理這些 "突發(fā)" 事件. 于是, 基于 事件循環(huán)機(jī)制 的 單線程模型 就出現(xiàn)了。

Dart的事件循環(huán)機(jī)制由一個(gè)消息循環(huán)(Event Looper)和兩個(gè)消息隊(duì)列構(gòu)成。兩個(gè)消息隊(duì)列分別是事件隊(duì)列(Event Queue)和微任務(wù)隊(duì)列(Microtask Queue)。

1.Event Looper

Dart在執(zhí)行完main函數(shù)后, Event Looper就開始工作, Event Looper優(yōu)先全部執(zhí)行完 Microtask Queue中的event, 直到Microtask Queue為空時(shí), 才會(huì)執(zhí)行Event Looper中的 event, Event Looper為空時(shí)才可以退出循環(huán)。

2.Event Queue
  • Event Queue的 event 來源于外部事件或Future
  • 外部事件:例如輸入/輸出, 手勢(shì), 繪制, 計(jì)時(shí)器, Stream等,
  • Future:用于自定義Event Queue事件。

對(duì)于外部事件, 一旦沒有任何 microtask 要執(zhí)行, Event loop 才會(huì)考慮 event queue 中的第一項(xiàng), 并且將會(huì)執(zhí)行它。

  • 案例:向Event Queue中添加事件任務(wù)
Future(() {
  // 事件任務(wù)
});
3.Microtask Queue
  • Microtask Queue的優(yōu)先級(jí)高于Event Queue.
  • 使用場(chǎng)景: 想要在稍后完成一些任務(wù)(microtask) 但又希望在執(zhí)行下一個(gè)事件(event)之前執(zhí)行.

Microtask 一般用于非常短的內(nèi)部異步動(dòng)作, 并且任務(wù)量非常少, 如果微任務(wù)非常多, 就會(huì)造成 Event Queue 排不上隊(duì), 會(huì)阻塞 Event Queue 的執(zhí)行(如: 用戶點(diǎn)擊沒有反應(yīng)). 所以, 大多數(shù)情況下優(yōu)先考慮使用 Event Queue, 整個(gè) Flutter 源代碼僅引用 scheduleMicroTask() 方法 7 次.

  • 案例:向 Microtask Queue 添加微任務(wù):
scheduleMicrotask(() {
  // 微任務(wù)
});

二、Future

1. Future 實(shí)例有 3 個(gè)常用方法:
  • then((value){...}): 正常運(yùn)行時(shí)執(zhí)行
  • catchError((err){...}): 出現(xiàn)錯(cuò)誤時(shí)執(zhí)行
  • whenComplete((){...}): 不管成功與否都會(huì)執(zhí)行
2.鏈?zhǔn)秸{(diào)用

Future 可以在 then()方法中返回另一個(gè) Future 實(shí)例, 從而達(dá)到鏈?zhǔn)秸{(diào)用的效果, 這對(duì)那些有數(shù)據(jù)關(guān)聯(lián)的網(wǎng)絡(luò)請(qǐng)求很有用

3.其他

Future 除了默認(rèn)構(gòu)造器外, 還提供了幾個(gè)常用的命名構(gòu)造器:

  • Future.value(): 創(chuàng)建一個(gè)返回具體數(shù)據(jù)的 Future 實(shí)例
  • Future.error(): 創(chuàng)建一個(gè)返回錯(cuò)誤的 Future 實(shí)例
  • Future.delayed(): 創(chuàng)建一個(gè)延時(shí)執(zhí)行的 Future 實(shí)例

三、async/await

1、基本使用

  • await 必須在 async 函數(shù)中使用
  • async 函數(shù)返回的結(jié)果必須是一個(gè) Future

四、isolate

所有的 Dart 代碼都是在 isolate 中運(yùn)行的, 它就是機(jī)器上的一個(gè)小空間, 具有自己的私有內(nèi)存塊和一個(gè)運(yùn)行著 Event Looper 的單個(gè)線程. 每個(gè) isolate 都是相互隔離的, 并不像線程那樣可以共享內(nèi)存. 一般情況下, 一個(gè) Dart 應(yīng)用只會(huì)在一個(gè) isolate 中運(yùn)行所有代碼, 但如果有特殊需要, 可以開啟多個(gè):

1、創(chuàng)建 isolate (Dart API)

Dart 默認(rèn)提供了 Isolate.spawn(entryPoint, message) 用于開啟 isolate, 通過源碼可以知道形參 message 其實(shí)是 形參 entryPoint 對(duì)應(yīng)的函數(shù)執(zhí)行時(shí)需要的參數(shù)。
使用 Isolate.spawn(entryPoint, message) 開啟 isolate, 并指定要執(zhí)行的任務(wù):

import 'dart:isolate';
main(List<String> args) {
  print("main start");
  Isolate.spawn(calc, 100);
  print("main end");
}

void calc(int count) {
  var total = 0;
  for (var i = 0; i < count; i++) {
    total += i;
  }
  print(total);
}
2、isolate 通信 (單向)

isolate 間可以一起工作的唯一方法是通過來回傳遞消息. 一般情況下, 子isolate 會(huì)將運(yùn)行結(jié)果通過管道以消息的形式發(fā)送到 主isolate, 并在 主isolate 的 Event Looper 中處理該消息, 這時(shí)就需要借助 ReceivePort 來處理消息的傳遞了:

  • 在啟動(dòng) 子isolate 時(shí), 將 主isolate 的發(fā)送管道(SendPort)作為參數(shù)傳遞給 子isolate.
  • 子isolate 在執(zhí)行完畢時(shí), 可以利用管道(SendPort)給 主isolate 發(fā)送信息.
import 'dart:isolate';
main(List<String> args) async {
  print("main start");

  // 1. 創(chuàng)建管道
  var receivePort = ReceivePort();

  // 2. 創(chuàng)建isolate
  Isolate isolate = await Isolate.spawn(foo, receivePort.sendPort);

  // 3. 監(jiān)聽管道
  receivePort.listen((message) {
    print(message);
    // 不再使用時(shí), 關(guān)閉管道
    receivePort.close();
    // 不再使用時(shí), 將 isolate 殺死
    isolate.kill();
  });

  print("main end");
}

void foo(SendPort sendPort) {
  sendPort.send("Hello lqr");
}
3、創(chuàng)建 isolate (Flutter API)

Flutter 提供了更為方便的開啟 isolate 的 API: compute() 函數(shù). 以下是示例代碼:

main(List<String> args) async {
  int result = await compute(powerNum, 5);
  print(result);
}

int powerNum(int num) {
  return num * num;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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