【问题标题】:Flutter & Dart: What is the correct way to manage obtained data from a computation made in an Isolate?Flutter & Dart:管理从 Isolate 中进行的计算获得的数据的正确方法是什么?
【发布时间】:2021-07-14 19:43:02
【问题描述】:

在 Dart 中进行昂贵的计算时,强烈建议启动额外的 isolates。我知道,由于隔离不共享任何状态,如果您想在它们之间创建通信,则可以使用SendPortReceivePort 将消息从一个传递到另一个。但是,当在另一个 Isolate 中进行计算时,在这个新创建的 isolate 进程中,实际上可以初始化一个已经创建的变量,例如 Singleton 的变量,对吧?

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

【问题讨论】:

    标签: flutter dart-isolates


    【解决方案1】:

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

    即使分析器可能允许您在一个隔离变量中修改一个变量,您也不会得到您期望的行为。可以将分离物视为完全不同的过程。

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

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

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

    0
    1
    In isolate: 1
    

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

    0
    1
    In isolate: 0
    

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


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


    您将此问题标记为,所以我猜您正在使用 Flutter。如果您正在使用单个输出进行单个大型计算,那么使用 Flutter 的 compute 方法可能是使用隔离的最简单方法,因为它消除了您使用端口的需要。但是,它可能会受到限制,并且像我上面所做的那样使用完全隔离实现通常很有用。

    【讨论】:

    • 感谢您的回答!非常清楚。但是,关于计算方法,我不得不说,当你的意思是它不需要使用端口时,你的意思是它不能使用它们吗?因为实际上可以将计算与端口一起使用。
    • @IvánYoed 不,我的意思正如我所说,它消除了需要。由于compute 返回一个Future,它在传递给它的计算返回时完成,因此无需使用端口来确定隔离何时完成。如果你愿意,你可以使用带有compute 的端口,但我个人会在那个时候进行正常的隔离。
    • 太棒了。所以现在一切都清楚了。我接受你的回答。再次感谢。
    • 正如可以推断的那样,作为对这个答案的补充,您前面的示例在使用 compute 方法而不是 Isolate.spawn 时表现相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 2010-12-15
    • 2012-05-07
    • 2012-03-14
    相关资源
    最近更新 更多