Flutter开发进阶:Flutter事件循环机制与异步

Dart是基于 事件循环机制的单线程模型, 所以Dart中没有多线程, 也就没有主线程与子线程之分。

  • 单线程模型:一条执行线上同时只能执行一个任务,如果有耗时任务则需要放入队列异步执行。
  • 多线程:充分利用处理器的多核优势进行并行计算。

一、事件循环机制

对于用户点击, 滑动, 硬盘IO访问等事件, 你不知道何时发生或以什么顺序发生, 所以得有一个永不停歇且不能阻塞的循环来等待处理这些 "突发" 事件. 于是, 基于 事件循环机制 的 单线程模型 就出现了。

Dart的事件循环机制由一个消息循环(Event Looper)和两个消息队列构成。两个消息队列分别是事件队列(Event Queue)和微任务队列(Microtask Queue)。

1.Event Looper

Dart在执行完main函数后, Event Looper就开始工作, Event Looper优先全部执行完 Microtask Queue中的event, 直到Microtask Queue为空时, 才会执行Event Looper中的 event, Event Looper为空时才可以退出循环。

2.Event Queue
  • Event Queue的 event 来源于外部事件或Future
  • 外部事件:例如输入/输出, 手势, 绘制, 计时器, Stream等,
  • Future:用于自定义Event Queue事件。

对于外部事件, 一旦没有任何 microtask 要执行, Event loop 才会考虑 event queue 中的第一项, 并且将会执行它。

  • 案例:向Event Queue中添加事件任务
Future(() {
  // 事件任务
});
3.Microtask Queue
  • Microtask Queue的优先级高于Event Queue.
  • 使用场景: 想要在稍后完成一些任务(microtask) 但又希望在执行下一个事件(event)之前执行.

Microtask 一般用于非常短的内部异步动作, 并且任务量非常少, 如果微任务非常多, 就会造成 Event Queue 排不上队, 会阻塞 Event Queue 的执行(如: 用户点击没有反应). 所以, 大多数情况下优先考虑使用 Event Queue, 整个 Flutter 源代码仅引用 scheduleMicroTask() 方法 7 次.

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

二、Future

1. Future 实例有 3 个常用方法:
  • then((value){...}): 正常运行时执行
  • catchError((err){...}): 出现错误时执行
  • whenComplete((){...}): 不管成功与否都会执行
2.链式调用

Future 可以在 then()方法中返回另一个 Future 实例, 从而达到链式调用的效果, 这对那些有数据关联的网络请求很有用

3.其他

Future 除了默认构造器外, 还提供了几个常用的命名构造器:

  • Future.value(): 创建一个返回具体数据的 Future 实例
  • Future.error(): 创建一个返回错误的 Future 实例
  • Future.delayed(): 创建一个延时执行的 Future 实例

三、async/await

1、基本使用

  • await 必须在 async 函数中使用
  • async 函数返回的结果必须是一个 Future

四、isolate

所有的 Dart 代码都是在 isolate 中运行的, 它就是机器上的一个小空间, 具有自己的私有内存块和一个运行着 Event Looper 的单个线程. 每个 isolate 都是相互隔离的, 并不像线程那样可以共享内存. 一般情况下, 一个 Dart 应用只会在一个 isolate 中运行所有代码, 但如果有特殊需要, 可以开启多个:

1、创建 isolate (Dart API)

Dart 默认提供了 Isolate.spawn(entryPoint, message) 用于开启 isolate, 通过源码可以知道形参 message 其实是 形参 entryPoint 对应的函数执行时需要的参数。
使用 Isolate.spawn(entryPoint, message) 开启 isolate, 并指定要执行的任务:

import 'dart:isolate';
main(List 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 会将运行结果通过管道以消息的形式发送到 主isolate, 并在 主isolate 的 Event Looper 中处理该消息, 这时就需要借助 ReceivePort 来处理消息的传递了:

  • 在启动 子isolate 时, 将 主isolate 的发送管道(SendPort)作为参数传递给 子isolate.
  • 子isolate 在执行完毕时, 可以利用管道(SendPort)给 主isolate 发送信息.
import 'dart:isolate';
main(List args) async {
  print("main start");

  // 1. 创建管道
  var receivePort = ReceivePort();

  // 2. 创建isolate
  Isolate isolate = await Isolate.spawn(foo, receivePort.sendPort);

  // 3. 监听管道
  receivePort.listen((message) {
    print(message);
    // 不再使用时, 关闭管道
    receivePort.close();
    // 不再使用时, 将 isolate 杀死
    isolate.kill();
  });

  print("main end");
}

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

Flutter 提供了更为方便的开启 isolate 的 API: compute() 函数. 以下是示例代码:

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

int powerNum(int num) {
  return num * num;
}

你可能感兴趣的:(Flutter开发进阶:Flutter事件循环机制与异步)