Каков наилучший способ отследить состояние изолята в дротике?

Я пытаюсь отследить, работает ли изолят в настоящее время или нет (и в будущем произойдет ли ошибка) с помощью 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";
        }
      });
});

Карта "items" содержит 3 значения, каждое из которых имеет свое имя: item1, item2, item3

Когда я запускаю этот код, единственный вывод, который я получаю: "Элемент завершен: item3"

Я ожидал следующий вывод (не обязательно по порядку, так как изоляты асинхронны): "Элемент завершен: элемент1" "Элемент завершен: элемент2" "Элемент завершен: элемент3"

Вот код, выполняемый в изолятах:

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

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

Заранее спасибо!

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

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

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


Надеюсь это поможет,

-Ivan

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

ДартДок из 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'));
}
Другие вопросы по тегам