2015-06-23 3 views
2

Я действительно новичок в Дарте, а также в программировании. Я пытаюсь разработать программу в Dart с использованием изолятов. Мое намерение - сравнить его производительность снова в той же программе, но написано на Java с потоками.Как использовать результаты из разных изолятов в основном изоляте?

программа

дротик выглядит так до сих пор:

  1. main.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. myIsolate.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 я не могу понять, как это сделать в изолятах.

Любые идеи?

ответ

1

Вам нужно подождать, пока все потоки (из ваших портов) будут завершены. Один из способов сделать это является чем-то вроде этого:

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

Для вашей задачи, если вы ждете точных значений, то можно определить, только фьючерсы на эти ценности вам нужно, и завершить их, не дожидаясь ваших изолятов (и их потоки), чтобы закончить.

Для этого просто переместите c*.complete(<value>) в соответствующий callback(). Нечто подобное (не проверено):

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}"); 
}); 
+0

Большое спасибо @Mike! Это было именно то, что я искал. Я тестировал hehre, и он работал как шарм :) – jlggross

+0

На этой последней части 'Future.wait ([c1.future, c2.future]).then ((_) {...}); 'Я также добавил выражение ** await **, которое позволит мне продолжить выполнение в главном изоляте, как если бы я выполнял его синхронно. Таким образом, окончательный код выглядит следующим образом: 'await Future.wait ([c1.future, c2.future]). Then ((_) {...});'. – jlggross

+0

Да, вы правы, я забыл поставить 'await' или' .then() 'там. Кстати, вам нужен только один из них, а не оба. Вы можете использовать 'await', а затем поместить зависимый код после него или использовать' .then() 'без' await', потому что они делают почти то же самое, только обработка ошибок немного отличается. – Mike

1

Если вы хотите чего-то ждать в Dart, что что-то должно быть в будущем. Вы можете конвертировать событие потока или порта в будущее разными способами. Если вы сомневаетесь, вы всегда можете использовать Completer для создания будущего из любого другого события. В этом случае это можно сделать проще, потому что вам просто нужно одно событие из каждого потока, и вы можете использовать Stream.first (или или Stream.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}"); 
    }); 
} 

Вот я и ждать возвращения spawnUriFuture, поскольку она может содержать ошибки, если ваш изолят не икру правильно.

Вы также можете использовать некоторые вспомогательные функции в изолированном пакете.

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}"); 
} 
+0

Спасибо @ Irn. Ваше решение сработало для меня! – jlggross