Flutter|dart异步实现机制
Fang 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
。
- 从main函数开始运行,待main函数执行完毕后,event looper开始工作
- event looper优先遍历执行微任务队列所有事件,直到微任务队列为空
- event looper才遍历执行事件队列中的所有事件,直到事件队列为空
- 视情况退出循环
当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
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