简介
Isolate 是 Dart 中实现并发的方式。每个 Isolate 都有自己的内存堆和事件循环,Isolate 之间通过消息传递进行通信。
基本概念
创建 Isolate
import 'dart:isolate';
void isolateFunction(SendPort sendPort) {
// Isolate 中的计算
int result = complexComputation();
// 发送结果回主 Isolate
sendPort.send(result);
}
Future<void> main() async {
// 创建通信端口
ReceivePort receivePort = ReceivePort();
// 启动新的 Isolate
await Isolate.spawn(isolateFunction, receivePort.sendPort);
// 接收结果
final result = await receivePort.first;
print('Result: $result');
}
双向通信
import 'dart:async';
import 'dart:isolate';
void isolateFunction(SendPort sendPort) {
// 创建接收端口
final receivePort = ReceivePort();
// 发送此 Isolate 的 SendPort 到主 Isolate
sendPort.send(receivePort.sendPort);
// 处理接收到的消息
receivePort.listen((message) {
if (message is int) {
final result = message * 2;
sendPort.send(result);
}
});
}
Future<void> main() async {
final receivePort = ReceivePort();
final isolate = await Isolate.spawn(isolateFunction, receivePort.sendPort);
// 注意:ReceivePort 是单订阅流,只能 listen 一次,
// 不能像普通变量那样反复 await receivePort.first。
// 所以用一次订阅同时处理两件事:收到对方的 SendPort 就发请求,收到数字回包就结束等待
final completer = Completer<int>();
receivePort.listen((message) {
if (message is SendPort) {
message.send(42);
} else if (message is int) {
completer.complete(message);
}
});
final result = await completer.future;
print('Result: $result'); // 84
receivePort.close();
isolate.kill();
}
数据传递
可传递的数据类型
// 基本类型
sendPort.send(42);
sendPort.send('Hello');
sendPort.send(true);
// 集合
sendPort.send([1, 2, 3]);
sendPort.send({'a': 1, 'b': 2});
// SendPort
sendPort.send(anotherSendPort);
// 自定义类型(需要实现特定接口)
class TransferableData {
final int id;
final String data;
TransferableData(this.id, this.data);
// 转换为可传输格式
Map<String, dynamic> toMap() {
return {
'id': id,
'data': data,
};
}
// 从可传输格式恢复
factory TransferableData.fromMap(Map<String, dynamic> map) {
return TransferableData(
map['id'] as int,
map['data'] as String,
);
}
}
错误处理
异常捕获
import 'dart:isolate';
void isolateFunction(SendPort sendPort) {
try {
throw Exception('Something went wrong');
} catch (e) {
sendPort.send({'error': e.toString()});
}
}
Future<void> main() async {
final receivePort = ReceivePort();
try {
await Isolate.spawn(isolateFunction, receivePort.sendPort);
final result = await receivePort.first;
if (result is Map && result.containsKey('error')) {
print('Error in isolate: ${result['error']}');
}
} catch (e) {
print('Error spawning isolate: $e');
}
}
完整示例
import 'dart:isolate';
import 'dart:math';
// 计算密集型任务
class ComputeTask {
final int start;
final int end;
ComputeTask(this.start, this.end);
Map<String, dynamic> toMap() => {
'start': start,
'end': end,
};
factory ComputeTask.fromMap(Map<String, dynamic> map) =>
ComputeTask(map['start'], map['end']);
}
// 计算结果
class ComputeResult {
final int sum;
final Duration duration;
ComputeResult(this.sum, this.duration);
Map<String, dynamic> toMap() => {
'sum': sum,
'duration': duration.inMilliseconds,
};
factory ComputeResult.fromMap(Map<String, dynamic> map) =>
ComputeResult(
map['sum'],
Duration(milliseconds: map['duration']),
);
}
// Isolate 工作函数
void computeIsolate(SendPort sendPort) {
final receivePort = ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((message) {
// 消息协议:[任务 Map, 本次请求的专属回复端口]
if (message is List && message.length == 2) {
final task = ComputeTask.fromMap(message[0] as Map<String, dynamic>);
final replyTo = message[1] as SendPort;
final stopwatch = Stopwatch()..start();
// 执行计算密集型任务
int sum = 0;
for (int i = task.start; i <= task.end; i++) {
sum += i;
// 模拟复杂计算
sum += sqrt(i).floor();
}
stopwatch.stop();
final result = ComputeResult(sum, stopwatch.elapsed);
// 回复发给这次请求的专属端口,而不是 spawn 时的端口
replyTo.send(result.toMap());
}
});
}
class ComputeManager {
SendPort? _sendPort;
ReceivePort? _receivePort;
Isolate? _isolate;
Future<void> initialize() async {
_receivePort = ReceivePort();
_isolate = await Isolate.spawn(computeIsolate, _receivePort!.sendPort);
_sendPort = await _receivePort!.first;
}
Future<ComputeResult> compute(ComputeTask task) async {
if (_sendPort == null) {
throw StateError('ComputeManager not initialized');
}
// 每个请求配一个专属回复端口:响应只会回到这里,多任务并发也不会串消息。
// 注意不能直接 await _receivePort.first —— ReceivePort 是单订阅流,
// initialize() 里已经 listen 过一次,再订阅会抛 "Stream has already been listened to"
final responsePort = ReceivePort();
_sendPort!.send([task.toMap(), responsePort.sendPort]);
final resultMap = (await responsePort.first) as Map<String, dynamic>;
responsePort.close();
return ComputeResult.fromMap(resultMap);
}
void dispose() {
_receivePort?.close();
_isolate?.kill();
_sendPort = null;
_receivePort = null;
_isolate = null;
}
}
void main() async {
final manager = ComputeManager();
await manager.initialize();
// 执行多个计算任务
final tasks = [
ComputeTask(1, 1000000),
ComputeTask(1000001, 2000000),
ComputeTask(2000001, 3000000),
];
for (var task in tasks) {
try {
final result = await manager.compute(task);
print('Task ${task.start}-${task.end}:');
print('Sum: ${result.sum}');
print('Duration: ${result.duration.inMilliseconds}ms\n');
} catch (e) {
print('Error computing task: $e');
}
}
manager.dispose();
}
最佳实践
- 合理划分计算任务
- 注意数据传输开销
- 及时释放资源
- 处理好异常情况
- 避免过多的 Isolate
注意事项
- Isolate 之间不共享内存
- 注意数据序列化成本
- 合理控制 Isolate 数量
- 处理好生命周期
- 注意平台限制
实战视角:我的项目为什么没用 Isolate
说实话,我的几个 Flutter 项目里(flutter_brightness、某物流冷链项目、ygking_json_to_dart_model),一个都没用过 Isolate.spawn。这不是因为我不懂,而是因为都没到那个份上:
flutter_brightness读串口:SerialPortReader本来就是事件驱动的,数据来了才回调,主线程几乎不阻塞——Stream就够了,不需要 Isolate。ygking_json_to_dart_model生成代码:143 行的字符串拼接,几毫秒就完事。为几毫秒去 spawn 一个 Isolate,光是线程启动开销都比计算本身大。
什么时候才需要 Isolate?记住这条线(参考了 Medium 上一篇 Dart 并发指南的决策框架,改写成我的话):
- IO 等待(网络、文件、串口)→
async/await就够,根本不用 Isolate。IO 不占 CPU,只是在”等”。 - CPU 密集且一次性的(大 JSON 解析、图片压缩)→
compute(),Flutter 给你包好的”一次性后台线程”。 - CPU 密集且长期存在的(音视频编解码后台任务)→ 才轮到
Isolate.spawn自己管理。
新手最常见的误区是把”异步”和”多线程”混为一谈:await 不等于”换了个线程跑”,它只是在等的时候把线程让出来。先分清你的任务是”等”还是”算”——是”等”,async 就够;是”算”且超过一帧(16ms),再考虑 Isolate。我的项目全是”等”,所以一个 Isolate 都没写,这恰恰说明决策是对的。
参考:Medium《Mastering Dart Concurrency》
总结
Isolate 的心智模型其实就一句话:不共享内存,只传消息。上面完整示例里那个 [任务, 回复端口] 的消息协议,就是这句话的落地——连”回复发给谁”都得显式传过去,没有任何隐式共享。记住这个,Isolate 的 API 就剩不下多少东西了。
