Appearance
Dart Future / Event Loop / Isolate
Dart 的并发核心不是“线程池 + 回调地狱”,而是 单线程事件循环 + microtask queue + event queue + isolate 消息隔离。
代码索引
| 主题 | Lab 说明 | 源码 |
|---|---|---|
| event loop / microtask / event queue / isolate | dart-event-loop-isolate | event_loop_isolate_demo.dart |
为什么需要
Flutter / Dart 面试和实际业务里,这些问题几乎必问:
- 为什么
Future不是线程? Future.microtask和Future(() {})到底差在哪?await后面的代码什么时候恢复?- CPU 密集任务为什么会卡 UI?
- 什么时候必须上 isolate?
如果只会“Future 就是异步”,遇到卡顿、执行顺序、主线程阻塞问题会很难说清。
底层机制
1. 默认执行模型:单线程事件循环
Dart 默认在一个 isolate 内运行,核心调度模型是:
- 同步代码先跑完
- 再清空 microtask queue
- 再从 event queue 取任务执行
所以常见优先级大致是:
text
sync code
> microtask
> event queue future / timer / IO completion2. Future 不是线程
像下面这种:
dart
Future(() {
// ...
});默认只是把任务丢进当前 isolate 的 event queue,不是新线程。
3. microtask 会更早执行
例如:
dart
scheduleMicrotask(() => print('microtask'));
Future(() => print('event'));通常会先看到:
text
microtask
event因为 microtask queue 会在进入下一轮 event queue 前优先清空。
4. isolate 才是真正的并发隔离单元
isolate 特点:
- 独立内存
- 不共享对象
- 靠消息传递
- 更适合 CPU 密集任务
这也是 Flutter 中为什么:
- 网络请求异步通常不需要 isolate
- 但大 JSON 解析、图片处理、复杂计算有时要 isolate
Android / Flutter / Web / Backend 对照
| 维度 | Dart | Flutter | JS / Web | 后台 Java/Kotlin |
|---|---|---|---|---|
| 默认异步模型 | 单 isolate 事件循环 | UI isolate 事件循环 | event loop | 线程池 / 协程 / 事件循环按框架而定 |
| 更高优先级队列 | microtask | microtask | microtask / promise job | 无直接等价统一模型 |
| 普通异步队列 | event queue | event queue | macrotask | executor / dispatcher |
| 真正并发隔离单元 | isolate | isolate / compute | Web Worker | Thread / process |
常见场景
1. 页面启动时多个 Future 排序不符合预期
如果你同时用了:
scheduleMicrotaskFuture.microtaskFuture(() {})
执行顺序常常和直觉不一样。
对应 Lab:dart-event-loop-isolate · event_loop_isolate_demo.dart
2. Flutter UI 卡顿
如果 CPU 密集计算放在主 isolate:
Future语法看起来是异步- 但本质仍可能阻塞当前 isolate 的执行
这时要考虑:
Isolate.runcompute
3. 大量 JSON / 加解密 / 数据清洗
这类任务更适合 isolate,而不是只靠普通 Future 包一层。
常见坑
| 坑 | 现象 | 修法 |
|---|---|---|
把 Future 当线程 | 以为不会卡 UI | 先分清是否仍在当前 isolate |
| 滥用 microtask | 某些回调顺序异常、可读性差 | 只在必须抢优先级时使用 |
| 所有异步任务都上 isolate | 复杂度高、消息传递成本增加 | 只给 CPU 密集任务上 isolate |
认为 await 会立即切线程回来 | 顺序理解错误 | 理解它只是等待 future 完成后恢复 continuation |
与相近概念对比
| 概念 | 本质 | 适合场景 |
|---|---|---|
Future(() {}) | event queue 任务 | 普通异步调度 |
Future.microtask | microtask queue 任务 | 需要更高优先级的短逻辑 |
await | continuation 恢复点 | 顺序化异步代码 |
Isolate.run | 独立 isolate | CPU 密集任务 |
对应实验
各章节内已嵌入跳转链接;此处汇总全部 Lab:
| Lab | 说明 | 源码 |
|---|---|---|
| dart-event-loop-isolate | dart-event-loop-isolate | event_loop_isolate_demo.dart |
复习检查题
为什么说 Future 不是线程?
答:因为普通 Future 默认仍在当前 isolate 的事件循环中调度,只是把代码延后执行;它不会自动创建独立线程/独立内存执行单元。
Future.microtask为什么通常先于Future(() {})执行?答:因为 microtask queue 会在进入下一轮 event queue 前优先清空,所以 microtask 的优先级更高。
什么场景下应优先考虑 isolate?
答:CPU 密集任务,例如大 JSON 解析、复杂计算、图片处理、加解密等;纯 IO 异步通常不需要 isolate。
速记
- 同步先跑完
- microtask 先于 event queue
- Future 不是线程
- isolate 才是独立并发单元
- UI 卡顿先怀疑主 isolate 被 CPU 任务占住