You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart中更新长运行Isolate内的值?

解决方案

要在持续运行的while循环中接收SendPort发送的值,你可以通过以下方式实现:

  1. 用变量缓存最新值:在Isolate任务内定义一个变量存储最新收到的命令值;
  2. 监听消息流更新变量:通过listen方法监听命令端口的消息,收到新值时直接更新缓存变量,这个操作不会阻塞循环;
  3. 替换阻塞的sleep为非阻塞延迟:sleep会完全阻塞Isolate的事件循环,导致消息无法被处理,必须换成await Future.delayed,让事件循环有机会处理消息队列。

修改后的完整代码:

void main() async {
  final ReceivePort p = ReceivePort();
  var events = StreamQueue<dynamic>(p);
  // 修正顺序:先启动Isolate,再获取sendPort(原顺序会导致主线程一直等待)
  await Isolate.spawn(longTask, p.sendPort);
  SendPort sendPort = await events.next;
  
  sendPort.send(30);

  Future.delayed(const Duration(seconds: 10), () {
    sendPort.send(10);
  });
  Future.delayed(const Duration(seconds: 50), () {
    sendPort.send(30);
  });
}

Future<void> longTask(SendPort p) async {
  final commandPort = ReceivePort();
  p.send(commandPort.sendPort);

  int? latestValue;
  // 监听命令端口,收到消息就更新最新值
  commandPort.listen((message) {
    if (message is int) {
      latestValue = message;
      print("收到新值: $latestValue");
    }
  });

  // 持续循环,每秒执行一次
  while (true) {
    // 在这里使用最新值
    if (latestValue != null) {
      print("当前使用的值: $latestValue");
    } else {
      print("暂无命令值");
    }
    // 用非阻塞的延迟替代sleep,让事件循环能处理消息
    await Future.delayed(const Duration(seconds: 1));
  }
}

关键细节说明:

  • 修正Isolate启动顺序:原代码中先等待events.next再启动Isolate,会导致主线程一直等待(因为Isolate还未启动发送sendPort),所以必须先调用Isolate.spawn再获取sendPort;
  • listen的非阻塞特性:listen是异步监听,不会阻塞当前的while循环,新消息到来时会触发回调更新变量;
  • 替换sleep为Future.delayed:sleep属于阻塞式延迟,会暂停Isolate的所有操作(包括消息处理);而await Future.delayed会释放事件循环,让Isolate可以处理收到的消息,之后再继续循环。

内容的提问来源于stack exchange,提问作者Dwiyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:45:31