2015-03-25 2 views
2

Я пытаюсь отследить, работает ли изолятор в настоящее время или нет (и в будущем будет ли он выведен из строя), используя isolate.addOnExitListener (...). Однако, следующий фрагмент кода не работает, как я бы ожидать:Каков наилучший способ отслеживания состояния изолята в дротике?

items.forEach((name, item) async { 
     Isolate isolate = await Isolate.spawnUri(...); 
     item.status = "running"; 
     ReceivePort receivePort = new ReceivePort(); 
     isolate.addOnExitListener(receivePort.sendPort); 
     receivePort.listen((message){ 
     if (message == null) { 
      print("Item exited: ${item.name}"); 
      item.status = "stopped"; 
     } 
     }); 
}); 

«пункты» Карта содержит 3 значения, каждый с отличным названием: item1, item2, item3

Когда я запустить этот код, единственный выход, я получаю: «Item вышли: item3»

Я ожидал следующий вывод (не обязательно в порядке, так как изолят асинхронные): «Item вышли: item1» «Item вышли: item2 " «Item вышли: item3»

Вот код запущен в изолятов:

import 'dart:io'; 
main(List args) { 
    print('Hello world: standard out!'); 
    stderr.writeln('Hello world: standard error!'); 
} 

Похоже, замыкание теряется. Я здесь что-то не так? Есть ли лучший способ отслеживать состояние изоляции?

Заранее благодарен!

+0

Вы должны рассмотреть, начиная изолят в приостановленном состоянии, поэтому у вас есть время, чтобы настроить onExitListener. –

ответ

2

Если вы хочу убедиться, что вы можете установить прослушиватели onExit и onError в изоляторе до того, как какой-либо из кода изолята будет выполнен, тогда вы можете приостановить выделение. См. документацию о spawnUri.

Вот пример:

var isolate = await Isolate.spawnUri(myUri, args, message, paused: true); 
var receivePort = new ReceivePort(); 
isolate.addOnExitListener(receivePort.sendPort); 

receivePort.listen((message){ 
    if (message == null) { // A null message means the isolate exited 
    print("Item exited: ${item.name}"); 
    item.status = "stopped"; 
    } 
}); 

isolate.resume(isolate.pauseCapability); 

После регистрации соответствующих слушателей, вы можете начать вновь созданный изолируют с resume.

Это очень похоже на предложение начального рукопожатия, но в этом случае оно встроено в библиотеку.


Надеется, что это помогает,

-Ivan

+0

Я не знаю, как я пропустил это в документации! Это сработало отлично. –

1

У меня было такое же поведение, когда изолят не делал ничего примечательного (только один оператор печати). Кажется, он вышел до регистрации onExitListener.

DartDoc из onExitListener говорит

  • Если изолят уже мертв, ни одно сообщение не будет отправлено.

Код изолят

import 'dart:async' show Future, Stream; 

void main(List<String> args) { 
    new Future.delayed(new Duration(milliseconds: 500), 
    () =>print('isolate ${args}')); 
} 

С дополнительной задержки я получил желаемого на уведомления выхода. Задержка должна быть достаточно высокой :-(.

Вы можете сделать некоторое начальное рукопожатие, чтобы обеспечить изолят не выход, прежде чем все настроено правильно

import 'dart:isolate'; 
import 'dart:async' show Future, Stream, Completer; 
import 'dart:io' as io; 

class Item { 
    String name; 
    String status; 
    Item(this.name); 
} 

void main() { 
    final items = {'a': new Item('a'), 'b': new Item('b'), 'c': new Item('c')}; 
    items.forEach((name, item) async { 
    ReceivePort receivePort = new ReceivePort(); 
    SendPort sendPort = receivePort.sendPort; 
    Isolate isolate = await Isolate.spawnUri(
     Uri.parse('isolate.dart'), [sendPort, name], null); 
    receivePort.listen((message) { 
     if (message is SendPort) { 
     message.send('connected'); 
     } else if (message == null) { 
     print("Item exited: ${item.name}"); 
     item.status = "stopped"; 
     } else { 
     print("Message: ${message}"); 
     } 
    }); 
    isolate.addOnExitListener(receivePort.sendPort); 
    item.status = "running"; 
    }); 
} 
import 'dart:isolate'; 

void main(List<String> args) { 
    SendPort sendPort = (args[0] as SendPort); 
    var receivePort = new ReceivePort(); 
    sendPort.send(receivePort.sendPort); 
    // keeps the isolate alive at least until the first messgae arrives 
    receivePort.first.then((e) => print('isolate received: $e')); 
} 
+1

Это правда, что мертвые изоляты не могут ответить. Я бы, вероятно, использовал метод «Isolate.ping», чтобы получить ответ после отправки события «addOnExitListener» (это то, что делает 'package: isolate'' IsolateRunner'). Если вы не получите ответ ping либо до некоторого необоснованного тайм-аута (например, второго), тогда предположите, что изоляция мертва. В общем, порты отправки похожи на необработанные IP-пакеты - загораются и забываются - поэтому для любой «надежной» связи вам нужно сначала поставить протокол, например TCP, а в некоторых случаях вам просто нужно предположить, что изоляция мертва поскольку он не ответил вовремя. – lrn