引言
为什么我们需要了解 Event Loop?
"我们在优化 Flutter 性能时,常常听到两个关键词:Isolate 和 Event Loop 。
Isolate 解决了并行的问题,但它内部的任务执行顺序是谁决定的?------这就是 Event Loop。"
1、先回顾 Isolate 的作用
-
Flutter/Dart 中没有真正的多线程共享内存。
-
每个 Isolate(隔离体) 都有:
-
自己的内存堆;
-
自己的线程;
-
自己的事件循环(Event Loop)。
-
Isolate 的本质 :
是一个"独立的小世界"------不共享状态,通过消息通信。
2、 过渡提问(引出 Event Loop)
"那么问题来了------在一个 Isolate 里,
Future
、Stream
、Timer
、I/O
这些异步任务,是怎么排队、怎么调度的?"
答案就是:
Event Loop(事件循环),它是 Isolate 内部的"心脏",不断从队列中取任务来执行。
Event Loop 是什么
概念
Event Loop 是 Dart 的异步任务调度机制 。
它驱动应用不断执行异步事件,让程序在单线程中看起来"并发"。
Dart 的 Event Loop 有两个核心队列:
队列类型 | 描述 | 常见来源 |
---|---|---|
Microtask Queue | 存放需要立即执行的轻任务 | scheduleMicrotask() 、Future.then() |
Event Queue | 存放需要按顺序执行的异步任务 | Future(() {}) 、Timer 、I/O、用户输入等 |
Event Loop 的工作机制
每个 Isolate 内部的执行循环大致是这样的:
while (true) {
// 1、 先执行所有微任务
while (microtaskQueue.notEmpty) {
run(microtaskQueue.removeFirst());
}
// 2、 执行一个事件任务
run(eventQueue.removeFirst());
}
简化理解:
- 微任务(microtask)插队执行。
- 事件任务(event)排队轮流执行。
- 微任务队列清空 → 才会轮到事件队列。
实际例子:为什么微任务优先?
Dart
import 'dart:async';
void main() {
print('A');
Future(() => print('B - event'));
scheduleMicrotask(() => print('C - microtask #1'));
Future(() => print('D - event'));
scheduleMicrotask(() => print('E - microtask #2'));
print('F');
}
输出结果:
A
F
C - microtask #1
E - microtask #2
B - event
D - event
执行顺序说明:
1️⃣ 同步任务 A
、F
先执行。
2️⃣ 执行所有微任务(C、E)。
3️⃣ 再执行事件任务(B、D)。
结论:
微任务优先;事件任务顺序执行。
执行顺序说明:
1️⃣ 同步任务 A
、F
先执行。
2️⃣ 执行所有微任务(C、E)。
3️⃣ 再执行事件任务(B、D)。
Event Loop vs Android Looper 对比
对比项 | Android Looper | Dart Event Loop |
---|---|---|
线程模型 | 每个线程一个 Looper | 每个 Isolate 一个 Event Loop |
队列数量 | 只有一个 MessageQueue | 有两个队列(microtask / event) |
调度逻辑 | 一次取一条消息 | 微任务清空 → 取一条事件任务 |
应用层面 | Handler 消息驱动 | Future/Stream 异步驱动 |
结论:
Event Loop 是 Dart 世界里的 Looper + Handler 的结合体,
但更"细粒度",有两个优先级队列。
为什么要关心 Event Loop
1️⃣ 避免 UI 卡顿
-
Flutter 主 Isolate 控制渲染。
-
如果 Event Loop 被长任务堵住 → 下一帧来不及执行 → 卡顿。
2️⃣ 避免微任务风暴
-
连续调用
scheduleMicrotask()
会饿死事件队列。 -
导致
Timer
、Stream
、I/O
等事件延迟。
3️⃣ 理解 async/await 行为
-
await
本质就是"让出执行权",把后续逻辑丢回 Event Queue。 -
所以它不会阻塞主线程。
4️⃣ 正确地做性能优化
-
CPU 密集任务放到 Isolate;
-
I/O 异步任务交给 Event Loop;
-
UI 主线程保持轻量。
Isolate 与 Event Loop 的关系总结
层级 | 职责 | 举例 |
---|---|---|
Isolate | 并行执行(多线程级别) | 把重计算丢出去 |
Event Loop | 异步调度(单线程内) | 安排 Future、Stream、Timer 顺序 |
🧠 记一句话:
Isolate 解决"谁来干活",Event Loop 解决"活怎么排队"。
实践建议(总结)
✅ I/O 操作 :直接使用 async/await(交给 Event Loop)
✅ CPU 密集型任务 :使用 Isolate.run()
或 compute()
✅ 临时微任务 :仅在需要立即执行时使用 scheduleMicrotask()
❌ 不要 长时间堵塞 Event Loop(包括大循环、长计算)
✅ 让出执行权 :可使用 await Future(() {})
分帧执行任务
总结
Flutter 的性能秘诀在于"单线程异步驱动"。
Isolate 是 Dart 并发的根基。
Event Loop 是每个 Isolate 的心脏。
它通过两条队列不断循环,让 UI 流畅、异步顺滑。
记住这句:
👉 I/O 用 Event Loop,CPU 用 Isolate,微任务要少而快。