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<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 会将运行结果通过管道以消息的形式发送到 主isolate, 并在 主isolate 的 Event Looper 中处理该消息, 这时就需要借助 ReceivePort 来处理消息的传递了:
- 在启动 子isolate 时, 将 主isolate 的发送管道(SendPort)作为参数传递给 子isolate.
- 子isolate 在执行完毕时, 可以利用管道(SendPort)给 主isolate 发送信息.
import 'dart:isolate';
main(List<String> 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<String> args) async {
int result = await compute(powerNum, 5);
print(result);
}
int powerNum(int num) {
return num * num;
}
网友评论