Skip to content

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);
});

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) { /* 握手 / 业务统一处理 */ });

4. 运行方式 ​

bash
cd labs/dart/host
dart run bin/runtime_concurrency/isolate_message_passing_demo.dart

5. 预期现象 ​

  • 子 isolate 回传 [999, 2, 3, 4],但主 isolate 的 myList 仍是 [1, 2, 3, 4](深拷贝)
  • 子 isolate 完成 sum(0..999999) 计算并回传结果(CPU 重活搬离主 isolate)
  • TransferableTypedData materialize 拿回 100 字节

6. 常见误区 ​

误区实际情况
isolate 之间共享对象不共享堆——消息是深拷贝副本(或 TransferableTypedData 转移所有权)
ReceivePort 可以多次订阅单订阅流,first + take 混用直接抛异常
传大数据成本低深拷贝有成本;大数据应整体搬到子 isolate 计算,而非传回传去

7. 对应知识库文档 ​

8. 完整源码 ​

站点构建时间:2026/8/24 23:43:17