Appearance
dart-isolate-message-passing
1. 实验目标
用最小 Dart CLI 验证 Isolate 消息传递(对应 docs/01-runtime-concurrency/14):
Isolate.spawn+SendPort/ReceivePort:跨 isolate 单向传消息- 深拷贝副本:子 isolate 修改收到的 List,主 isolate 数据不受影响
- 双向通信:两个 isolate 各自持有一个 port 对完成握手
TransferableTypedData:大数据零拷贝转移所有权
2. 工程要点
- 纯 Dart
bin/入口,不依赖 Flutter UI childIsolate(SendPort):子 isolate 先回传自己的SendPort(双向握手),再listen处理业务消息- 深拷贝证明:子 isolate 把收到的 List 首元素改成 999,主 isolate 原 List 不变
- 注意:
ReceivePort是单订阅流,只能用一次listen(first与take混用会抛 "Stream has already been listened to")
3. 关键实现速览
3.1 双向握手 + 深拷贝证明
为什么看这段:展示 isolate 通信的标准模式——子 isolate 回传自己的 SendPort 完成双向,消息传递是深拷贝。
dart
void childIsolate(SendPort mainPort) {
final childPort = ReceivePort();
mainPort.send(childPort.sendPort); // 握手:回传自己的 port
childPort.listen((message) {
final data = (message[1] as List).cast<int>();
data[0] = 999; // 修改"副本"
mainPort.send(['echo_back', data, '我改了首元素']);
});
}
// 主 isolate:单次 listen 处理握手与回复
final receivePort = ReceivePort();
await Isolate.spawn(childIsolate, receivePort.sendPort);
final childPortCompleter = Completer<SendPort>();
final replies = <dynamic>[];
receivePort.listen((m) {
if (m is SendPort) childPortCompleter.complete(m);
else replies.add(m);
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3.2 为什么必须单次 listen
为什么看这段:ReceivePort 是单订阅流,receivePort.first 之后再 take().toList() 会直接抛异常。
dart
// ❌ 错误:两次订阅
final childPort = await receivePort.first; // 第一次 listen
final replies = await receivePort.take(2).toList(); // ← 抛异常
// ✅ 正确:一次 listen,用 Completer 区分握手与业务消息
receivePort.listen((m) { /* 握手 / 业务统一处理 */ });1
2
3
4
5
6
2
3
4
5
6
4. 运行方式
bash
cd labs/dart/host
dart run bin/runtime_concurrency/isolate_message_passing_demo.dart1
2
2
5. 预期现象
- 子 isolate 回传
[999, 2, 3, 4],但主 isolate 的myList仍是[1, 2, 3, 4](深拷贝) - 子 isolate 完成
sum(0..999999)计算并回传结果(CPU 重活搬离主 isolate) TransferableTypedDatamaterialize 拿回 100 字节
6. 常见误区
| 误区 | 实际情况 |
|---|---|
| isolate 之间共享对象 | 不共享堆——消息是深拷贝副本(或 TransferableTypedData 转移所有权) |
| ReceivePort 可以多次订阅 | 单订阅流,first + take 混用直接抛异常 |
| 传大数据成本低 | 深拷贝有成本;大数据应整体搬到子 isolate 计算,而非传回传去 |