Flutter & Dart:管理从 Isolate 计算中获得的数据的正确方法是什么?

Flutter & Dart: What is the correct way to manage obtained data from a computation made in an Isolate?

在 Dart 中进行昂贵的计算时,强烈建议启动额外的 isolates. I know that, since isolates don't share any state, if you want to create communication between them, there is the possibility to pass a message from one to another by using SendPort and ReceivePort。但是,在另一个Isolate中进行计算时,在这个新创建的isolate的过程中实际上可以初始化一个已经创建的变量,例如Singleton的变量,对吧?

所以我的问题是:可以这样进行吗?管理从隔离计算中获得的数据的正确方法是什么?为什么?在新隔离区内进行计算时,我们是否应该始终只处理消息?

不,您不能从一个隔离区初始化另一个隔离区的变量。他们没有你提到的共享内存。 Isolate 之间唯一的通信方式是通过端口。

即使分析器可能允许您修改一个隔离区中的变量,但您不会得到预期的行为。 Isolates 可以被认为是完全不同的过程。

我做了一个例子来展示这个行为:

import 'dart:isolate';

Future<void> main(List<String> arguments) async {
  final single = Singleton();
  print(single.variable);

  single.variable = 1;
  print(single.variable);

  final port = ReceivePort();
  final isolate = await Isolate.spawn(isolateWork, port.sendPort);
  await for(dynamic message in port) {
    if(message == 'done') {
      isolate.kill();
      break;
    }
  }
}

void isolateWork(SendPort port) {
  final single = Singleton();
  print('In isolate: ${single.variable}');
  port.send('done');
}

class Singleton {
  int variable = 0;

  static final Singleton _singleton = Singleton._internal();

  factory Singleton() {
    return _singleton;
  }

  Singleton._internal();
}

这是一个简单的程序,它尝试使用单例来修改一个与派生的隔离物中的变量。如果有共享内存,当我第一次获得单例时,可能会期望以下输出,打印 0 的默认 variable 值,将 variable 更改为 1,然后在隔离中打印 variable

0
1
In isolate: 1

但是,由于这些 isolate 是完全独立的进程,因此生成的 isolate 有自己的单例实例,导致以下输出:

0
1
In isolate: 0

01 在主隔离中按预期打印,但生成的有自己的内存并使用单独的单例对象,因此它打印 0 即使它在主隔离中 1


正如您在上面的示例中看到的那样,我确实使用了端口,以便我的程序可以检测到隔离何时完成并优雅地终止进程。使用端口传递消息是在 isolate 之间传递数据的正确且唯一的方法。


您将此问题标记为 , so I'm guessing you're using Flutter. If you're doing a single, large computation with a single output, using Flutter's compute 方法可能是使用隔离的最简单方法,因为它消除了您使用端口的需要。但是,它可能会受到限制,并且像我上面那样使用完整的隔离实现通常很有用。