MultiTasker
MultiTasker

Reputation: 15

Strategy for waiting for isolates in dart

I have a piece of code that spawns x number of Isolates that are all running http servers. After starting the isolates my main application exits however. When testing I added the while(true) block as seen below, with an async await so the CPU doesn't run berserk. I totally forgot about it until months later when reviewing the code. It seems kind of unnecessary, although I could potentially add a kill-switch for all isolates, but it begs the question; how would I go about waiting for isolates to die off before exiting? As it is now, that while loop is keeping the entire application alive.

main() async {
  Server http_server = Server(80, 3);
  http_server.start();

  while(true) {
    await Future.delayed(Duration(seconds: 1));
  }
}

Upvotes: 1

Views: 1621

Answers (2)

lrn
lrn

Reputation: 71653

I'd use the onExit handlers of the other isolates to report when they die, then listen for that in the main isolate.

So:

var exitPort = RawReceivePort();
var liveIsolates = 0;
// Don't close port while still creating new isolates.
var isInitializing = true;
exitPort.handler = (_) {
  if (--liveIsolates == 0 && !isInitializing) exitPort.close();
};

try {
  for (var i = 0; i < x; i++) {
    liveIsolates++;
    ... Isolate.spawn(...., onExit: exitPort.sendPort) ...
  }
} finally {
  isInitializing = false;
  if (liveIsolates == 0) {
    // All isolate terminated already (or `x` was zero).
    exitPort.close();
  }
}

This will send a (null) message to the exitPort when each spawned isolate exits. When they're all done, the main isolate closes its last receive port, and can shut down too.

Upvotes: 2

julemand101
julemand101

Reputation: 31219

You should create a ReceivePort and then send a SendPort instance from this as argument to your Isolate instances (either create one ReceivePort for each Isolate or reuse the same depending on the amount of detail you want). By doing so, you can send data back to your main-isolate and your main-isolate will not stop because it has an open ReceivePort which prevents the isolate from stopping.

You can then e.g. make it so your HTTP servers can ask for the whole server to turn off. Or, you can just keep a ReceivePort instance open which will prevent the main isolate from stopping and without busy waiting (in that case, you don't need to send the SendPort instance into your isolates. Dart does not keep track of when ReceivePort should be closed, so you must manually close it when you think it is done).

Example:

import 'dart:async';
import 'dart:isolate';

void main() {
  ReceivePort receivePort = ReceivePort();
  receivePort.listen((message) {
    print('Got: $message');

    if (message == 'Goodbye') {
      print('Close ReceivePort and therefore also the program since '
          'nothing else are running that could trigger an event.');
      receivePort.close();
    }
  });

  Isolate.spawn(myIsolate, receivePort.sendPort);
}

void myIsolate(SendPort msg) {
  print('Running inside isolate. Wait 5 seconds before sending message back');
  Timer(const Duration(seconds: 5), () => msg.send('Goodbye'));
}

Upvotes: 3

Related Questions