在 Dart 里,单线程配合事件循环已经能处理大量并发任务,但一旦碰到密集计算,UI 线程仍可能被拖慢。Isolate 的价值,就在于把这类耗时工作挪到独立执行单元中处理。下面按“为什么要用、它到底是什么、怎么创建、如何管理”这条线梳理一遍,帮助你判断在实际项目里该用 spawn()、run() 还是 compute()。
为什么 Dart 需要 Isolate
Isolate 的出现,主要是在 Dart 单线程模型之外,补上真正并行执行的能力。
- 避免密集计算阻塞主线程:Dart 虽然能通过事件循环和任务队列组织并发,但任务本质上仍运行在同一线程里。遇到大循环、复杂解析或批量计算时,UI 依旧可能卡顿。
- 利用多核 CPU:现代设备通常具备多核处理能力,而单个执行线程无法天然吃满这些资源。把任务拆到多个 Isolate 中,才有机会并行运行。
- 减少共享状态问题:Isolate 之间不共享可变内存,通信依赖消息传递。这种模型天然绕开了传统多线程里常见的锁竞争和状态同步问题。
Isolate 到底是什么
可以把 Isolate 理解为 Dart 提供的独立并发执行单元。这里有两个关键词最重要:独立、通信。

为什么说它是独立的
每个 Isolate 都有自己的内存堆,彼此之间不共享可变数据,也就是常说的内存隔离。这意味着,即使不同 Isolate 中存在同名变量,也不会互相影响。
这种设计带来的直接好处是:并发执行时不需要围绕共享内存做额外防护,很多传统多线程编程里的复杂问题在这里被规避掉了。
Isolate 之间如何通信
既然内存隔离,数据交换就只能通过消息传递完成。Dart 里通常使用 SendPort 和 ReceivePort 建立通信通道。
- ReceivePort:消息接收端,负责监听来自其他 Isolate 的消息。
- SendPort:消息发送端,用于把数据发送给目标
ReceivePort。
消息传递采用拷贝机制或引用转移,传递的数据必须是可序列化的,例如基本类型、SendPort、List、Map 等。
另外,ReceivePort 本质上实现了 Stream,因此监听方式与 Stream 一致,通常使用 listen()。
Isolate 的三种创建方式
Dart 中常见的创建方式有三种:Isolate.spawn()、Isolate.run() 和顶层函数 compute()。它们的差别,主要在于控制粒度和封装程度。
1. `Isolate.spawn()`:适合需要精细控制的场景
Isolate.spawn() 是最基础的创建方式,适合你需要手动管理消息传递和生命周期的情况。
先看它涉及的两个通信对象:
- ReceivePort:作为消息监听器,接收其他 Isolate 发来的消息。
- SendPort:通常通过
receivePort.sendPort获取,用于向对应的ReceivePort发送数据。
`spawn()` 的主要参数
必传参数:
entryPoint:Isolate 的入口函数,必须为静态方法或顶层函数,传入参数类型必须与message参数一致。message:传递给entryPoint的参数,必须是可序列化的,例如基本类型、SendPort、List、Map等。
可选参数:
paused:为true时,新建 Isolate 启动后会暂停,后续需要调用Isolate.resume()恢复。errorsAreFatal:为true时,未捕获异常会直接导致 Isolate 终止。onExit:目标 Isolate 退出时,向指定SendPort发送null或exitCode。onError:发生未捕获异常时,向指定SendPort发送错误信息。debugName:为创建的 Isolate 指定调试名称。
`Isolate.spawn()` 示例
下面这个例子展示了如何启动一个新 Isolate,并通过端口把结果发回主 Isolate:
void buildIsolate() async{
final receivePort = ReceivePort();
// entryPoint参数 为需要传入参数为SendPort对象的函数。
// message参数为通过ReceivePort获取的SendPort。
final isolate = await Isolate.spawn((sendPort){sendPort.send('hello,Dart!');},receivePort.sendPort);
// 通过listen()监听听结果
receivePort.listen((data){print('接收到的信息为:$data');});
}
这类方式的优点是灵活,缺点是样板代码相对更多,适合需要自定义通信过程、错误处理或生命周期控制的任务。
2. `Isolate.run()`:适合一次性任务
Isolate.run() 用来简化一次性任务的执行,核心上可以看作对 Isolate.spawn() 的进一步封装。它会自动管理 Isolate 的生命周期,因此更适合“开一个任务、拿到结果、任务结束”的模式。
常见参数包括:
computation:要执行的同步任务或异步任务函数。debugName:用于标识该 Isolate 的名字。
`Isolate.run()` 同步任务示例
void buildIsolateWithRun() async {
final result = await Isolate.run((){
int sum = 0;
for (int i=0; i<100000000;i++){
sum += i;
}
return sum;
});
}
这类写法特别适合计算量大、但只需要返回一个最终结果的同步任务。
`Isolate.run()` 异步任务示例
void buildIsolateWithRun1() async {
final result = await Isolate.run(() async {
Dio dio = Dio();
final response = await dio.get('https://api.example.com/data');
return response;
});
}
原文也给出了异步网络请求的写法,说明 computation 既可以承载同步逻辑,也可以承载异步流程。
3. `compute()`:更高层的一次性封装
顶层函数 compute() 是 Dart 提供的便捷方法,专门用于简化一次性 Isolate 任务。它在调用层面比 Isolate.spawn() 更轻,也可以理解为建立在 Isolate.run() 之上的进一步封装。
它会自动处理 Isolate 生命周期、消息传递和资源释放,常见参数包括:
callback:在新 Isolate 中执行的函数,必须为顶层函数或静态方法。message:传递给callback的参数,必须是可序列化的。debugLabel:调试标签。
`compute()` 示例
void buildIsolateWithCompute() async {
// 传入参数message必须为可序列化的。
final result = await compute(sendMessage, [1,2,3]);
print(result);
}
int sendMessage(List<int> _list){
// 执行耗时计算任务
return _list[0];
}
如果你的需求只是“把一个独立函数丢到后台算完,再把结果拿回来”,那么 compute() 往往是最省事的选择。
`spawn()`、`run()`、`compute()` 怎么选
可以按任务复杂度来理解三者差异:

- 需要手动建立通信、监听多个消息、控制退出或异常处理,用
Isolate.spawn()。 - 只是执行一次性任务,希望自动管理生命周期,用
Isolate.run()。 - 任务形式非常简单,且更偏向“传入参数 + 返回结果”的调用方式,用
compute()。
它们并不是互斥关系,而是从底层能力到高层封装的不同抽象层级。
常用 Isolate 属性
除了创建方式,Isolate 本身也暴露了一些常用属性:
Isolate.current:获取当前 Isolate 实例。Isolate.packageConfig:获取当前 Isolate 的包配置。isolate.pauseCapability:暂停权限令牌。
注意:这里的 isolate 指的是 Isolate 实例。
void buildIsolate() async{
final receivePort = ReceivePort();
Isolate isolate = await Isolate.spawn((sendPort){sendPort.send('hello,Dart!');},receivePort.sendPort);
// 获取当前Isolate实例
Isolate currentIsolate = Isolate.current;
// 获取包配置
print(Isolate.packageConfig);
// 当前Isolate的暂停权限令牌。
Capability? pauseToken = isolate.pauseCapability;
}
如何暂停、恢复和终止 Isolate
在需要控制任务执行节奏时,可以使用 Isolate 的生命周期相关方法:

isolate.pause():暂停 Isolate,是异步方法,调用时需要await。isolate.resume():恢复 Isolate,需要传入权限令牌。isolate.kill():终止指定的 Isolate 实例。Isolate.exit():静态方法,终止当前正在运行的 Isolate。
void buildIsolate() async{
final receivePort = ReceivePort();
Isolate isolate = await Isolate.spawn((sendPort){sendPort.send('hello,Dart!');},receivePort.sendPort);
// 1.暂停Isolate
await isolate.pause();
Capability? pauseToken = isolate.pauseCapability;
if(pauseToken != null){
// 2.恢复Isolate
isolate.resume(pauseToken);
}
// 3.终止Isolate
isolate.kill();
// Isolate.exit();
}
这部分通常出现在你需要显式控制后台任务生命周期的场景,比如调试、任务编排或长时间运行的并发工作流。
总结
如果只抓核心,可以把 Isolate 理解为 Dart 用来处理耗时任务和并行计算的正式方案。它通过内存隔离避免共享状态问题,通过消息传递完成通信,再通过不同层级的 API 满足从底层控制到简单调用的多种需求。
| 分类 | 关键内容 |
|---|---|
| 创建方式 | Isolate.spawn()、Isolate.run()、compute() |
| 常用属性 | Isolate.current、Isolate.packageConfig、isolate.pauseCapability |
| 生命周期控制 | isolate.pause()、isolate.resume()、isolate.kill()、Isolate.exit() |
实际使用时,优先根据任务模式做选择:要控制通信细节就用 spawn(),要执行一次性任务就看 run() 或 compute()。这样既能避免主线程卡顿,也更容易把并发代码维持在可读、可维护的范围内。













