3

我对 Dart 和编程都很陌生。我正在尝试使用隔离在 Dart 中开发一个命令行程序。我的目的是将它的性能与同一个程序进行比较,但它是用 Java 编写的,带有线程。

到目前为止,Dart 程序看起来像这样:

  1. 主要.dart

    import "dart:async";
    import "dart:isolate";
    
    main() {    
        var rPort1 = new ReceivePort();
        var rPort2 = new ReceivePort();
    
        var p1 = 0;
        rPort1.listen((partial) {
            print("p1 ${partial}");
            p1 = partial;
            rPort1.close();
        });
        var p2 = 0;
        rPort2.listen((partial) {
           print("p2 ${partial}");
           p2 = partial;
           rPort2.close();
        });
    
        Isolate.spawnUri(new Uri.file("MyIsolate.dart"), [arg0, ...], rPort1.sendPort);
        Isolate.spawnUri(new Uri.file("MyIsolate.dart"), [arg0, ...], rPort2.sendPort);
    
        var p3 = p1 + p2;
        print("p3 ${p3}");
    }
    
  2. 我的隔离.dart

    import "dart:async";
    import "dart:isolate";
    
    main(args, SendPort port) {
        var partial = 0;
        // ... do stuff ...
        // args are used and partial is updated
        port.send(partial);
    }
    

输出如下所示:

p3 0
p1 -0.1168096561671553
p2 0.023709338284264223

如您所见,每个隔离的返回值是在主隔离完成执行之后出现的。我想要的是主要使用隔离的结果来进一步计算。

我不知道我错过了什么。我敢肯定这是非常愚蠢的事情,但我无法在这个问题上继续前进。在 Java 中获取每个线程的结果值很简单,但在 Dart 中我不知道如何在隔离中做到这一点。

有任何想法吗?

4

2 回答 2

3

您必须等到所有流(来自您的端口)都完成。这样做的一种方法是这样的:

import "dart:async";
import "dart:isolate";

main() {
  var rPort1 = new ReceivePort();
  var rPort2 = new ReceivePort();

  // Defining completers which would complete when Streams are finished   
  Completer c1 = new Completer();
  Completer c2 = new Completer();

  var p1 = 0;
  rPort1.listen((partial) {
    print("p1 ${partial}");
    p1 = partial;
    rPort1.close();
  }, onDone: ()=>c1.complete()); // Notice onDone callback here
  var p2 = 0;
  rPort2.listen((partial) {
    print("p2 ${partial}");
    p2 = partial;
    rPort2.close();

  }, onDone: ()=>c2.complete()); // And here

  Isolate.spawnUri(new Uri.file("my_isolate.dart"), [0], rPort1.sendPort);
  Isolate.spawnUri(new Uri.file("my_isolate.dart"), [0], rPort2.sendPort);

  // Waiting for both streams to complete before summing our results
  Future.wait([c1.future,c2.future]).then((_){
    var p3 = p1 + p2;
    print("p3 ${p3}");
  });
}

对于您的任务,如果您正在等待确切的值,您可以只为您需要的这些值定义 Futures,并在不等待您的隔离(及其流)完成的情况下完成它们。

为此,只需转到c*.complete(<value>)相应的 listen() 回调。类似的东西(未测试):

rPort1.listen((partial) {
  print("p1 ${partial}");
  c1.complete(partial);
  rPort1.close();
});
rPort2.listen((partial) {
  print("p2 ${partial}");
  c2.complete(partial);
  rPort2.close();
});

...

Future.wait([c1.future,c2.future]).then((result){
  var p3 = result[0] + result[1];
  print("p3 ${p3}");
});
于 2015-06-24T04:54:33.200 回答
2

如果你想在 Dart 中等待某些东西,那应该是一个未来。您可以通过多种不同的方式将流或端口事件转换为未来。如果有疑问,您始终可以使用 aCompleter从任何其他事件中创建未来。在这种情况下,它可以更容易地完成,因为您只需要每个流中的一个事件,并且您可以使用Stream.first(或Stream.lastStream.single)。

import "dart:async";
import "dart:isolate";

main() {
  var rPort1 = new ReceivePort();
  var rPort2 = new ReceivePort();

  Future.wait([
      Isolate.spawnUri(new Uri.file("my_isolate.dart"), ["0"], rPort1.sendPort)
             .then((_) => rPort1.first,
                   onError: (_) => rPort1.close()),
      Isolate.spawnUri(new Uri.file("my_isolate.dart"), ["0"], rPort2.sendPort)
             .then((_) => rPort2.first,
                   onError: (_) => rPort2.close()),
  ]).then((ps) {
     // Waiting for both streams to complete before summing our results
     var p3 = ps[0] + ps[1];
     print("p3 ${p3}");
  });
}

在这里我也等待spawnUri返回Future,因为如果您的隔离没有正确生成,它可能包含错误。

您还可以使用隔离包中的一些辅助函数。

import "dart:async";
import "dart:isolate";
import "package:isolate/isolate.dart";

main() async {
  // A SingleResponseChannel has a send-port and a result future,
  // and completes the future with the first port event.
  // Warning: Only closed when event is sent on port!
  // Consider setting a time-out on the channel.
  var c1 = new SingleResponseChannel();
  var c2 = new SingleResponseChannel();
  Isolate.spawnUri(new Uri.file("my_isolate.dart"), ["0"], c1.port);
  Isolate.spawnUri(new Uri.file("my_isolate.dart"), ["0"], c2.port);
  var p3 = await c1.result + await c2.result;
  print("p3 ${p3}");
}
于 2015-06-24T11:00:27.137 回答