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
0
和 1
在主隔离中按预期打印,但生成的有自己的内存并使用单独的单例对象,因此它打印 0
即使它在主隔离中 1
。
正如您在上面的示例中看到的那样,我确实使用了端口,以便我的程序可以检测到隔离何时完成并优雅地终止进程。使用端口传递消息是在 isolate 之间传递数据的正确且唯一的方法。
您将此问题标记为 flutter, so I'm guessing you're using Flutter. If you're doing a single, large computation with a single output, using Flutter's compute
方法可能是使用隔离的最简单方法,因为它消除了您使用端口的需要。但是,它可能会受到限制,并且像我上面那样使用完整的隔离实现通常很有用。
在 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
0
和 1
在主隔离中按预期打印,但生成的有自己的内存并使用单独的单例对象,因此它打印 0
即使它在主隔离中 1
。
正如您在上面的示例中看到的那样,我确实使用了端口,以便我的程序可以检测到隔离何时完成并优雅地终止进程。使用端口传递消息是在 isolate 之间传递数据的正确且唯一的方法。
您将此问题标记为 flutter, so I'm guessing you're using Flutter. If you're doing a single, large computation with a single output, using Flutter's compute
方法可能是使用隔离的最简单方法,因为它消除了您使用端口的需要。但是,它可能会受到限制,并且像我上面那样使用完整的隔离实现通常很有用。