Flutter|dart异步实现机制

2024/9/20 Flutter知识点

# dart异步实现机制

参考资料 Flutter 单线程的Dart为何能够流程运行UI (opens new window)

总结:异步IO+事件循环

# IO模型

  • 阻塞式调用
  • 非阻塞式调用

思路发展:

  • 多线程:CPU核心受限+同步问题
  • 非阻塞IO+轮询:CPU速度远大于IO速度,计算资源不匹配
  • IO多路转接:监听多个IO,一个IO有数据直接返回
  • 异步IO

# 事件循环

Dart在单线程中是以消息循环机制来运行的,包含两个任务队列,一个是微任务队列 microTask queue,另一个叫做事件队列 event queue

  1. 从main函数开始运行,待main函数执行完毕后,event looper开始工作
  2. event looper优先遍历执行微任务队列所有事件,直到微任务队列为空
  3. event looper才遍历执行事件队列中的所有事件,直到事件队列为空
  4. 视情况退出循环

当Flutter应用启动后,消息循环机制便启动了。首先会按照先进先出的顺序逐个执行微任务队列中的任务,当所有微任务队列执行完后便开始执行事件队列中的任务,事件任务执行完毕后再去执行微任务,如此循环往复,生生不息。

  • 微任务:由scheduleMicroTask建立的
  • 事件任务:封装一层Future,未来会完成的任务

# isolate隔离

在Isolate中,资源隔离做得非常好,每个Isolate都有自己的Event Loop与Queue,Isolate之间不共享任何资源,只能依靠消息机制通信,因此也就没有资源抢占问题。

假如不同的Isolate需要通信(单向/双向),就只能通过向对方的事件循环队列里写入任务,并且它们之间的通讯方式是通过port(端口)实现的,其中,Port又分为receivePort(接收端口)和sendPort(发送端口),它们是成对出现的。 Isolate之间通信过程:

void isolate1DoSomeThing() async{
  // 1. 当前Isolate创建一个ReceivePort对象,并获得对应的SendPort对象;
  var receivePort = ReceivePort();
  var sendPort = receivePort.sendPort;

  // 2. 创建一个新的Isolate,并实现新Isolate要执行的异步任务。
  // 同时,将当前Isolate的SendPort对象传递给新的Isolate,以便新Isolate使用这个SendPort对象向原来的Isolate发送事件

  // 调用Isolate.spawn创建一个新的Isolate,这是一个异步操作,因此使用await等待执行完毕
  // 函数签名: static Future<FlutterIsolate> spawn<T>(void entryPoint(T message), T message) async{...}
  var anotherIsolate = await Isolate.spawn<SendPort>(otherIsolateInit, receivePort.sendPort);

  // 3. 调用当前Isolate#receivePort的listen方法监听新的Isolate传递过来的数据。Isolate之间什么数据类型(T)都可以传递,不必做任何标记
  receivePort.listen((date) {
      print("Isolate 1 接受消息:data = $date");
      // 4. 消息传递完毕,关闭新创建的Isolate。
      anotherIsolate?.kill(priority: Isolate.immediate);
      anotherIsolate =null;
     receivePort.close();
  });
}

// 新Isolate要执行的异步任务
// 即调用当前Isolate的sendPort向其receivePort发送消息
void otherIsolateInit(SendPort sendPort) async {
  value = "Other Thread!";
  sendPort.send("BB");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Last Updated: 2024/11/22 17:43:46