๐ŸŽ“ A1Learner
๐Ÿ”
0 of 24 lessons completed

Dart Isolate Spawn

Isolate.spawn starts a separate isolate that stays alive to do work. The two isolates talk by sending messages through ports.

A worker that doubles a number

The worker receives a record holding the reply port and the number 21. It sends back double the number, and the main isolate prints the awaited reply.

import 'dart:isolate';

void worker((SendPort, int) message) {
  var (replyTo, value) = message;
  replyTo.send(value * 2);
}

Future<void> main() async {
  var port = ReceivePort();
  await Isolate.spawn(worker, (port.sendPort, 21));
  var reply = await port.first;
  print('reply: $reply');
}

A worker that shouts a word

The same pattern carries a word instead of a number. The worker sends back the word in capitals.

import 'dart:isolate';

void worker((SendPort, String) message) {
  var (replyTo, word) = message;
  replyTo.send(word.toUpperCase());
}

Future<void> main() async {
  var port = ReceivePort();
  await Isolate.spawn(worker, (port.sendPort, 'dart'));
  var reply = await port.first;
  print(reply);
}

The same worker spawned twice

Each spawn gets its own ReceivePort, so each reply stays separate. The replies print in input order, 9 then 16.

import 'dart:isolate';

void worker((SendPort, int) message) {
  var (replyTo, value) = message;
  replyTo.send(value * value);
}

Future<void> main() async {
  var firstPort = ReceivePort();
  var secondPort = ReceivePort();
  await Isolate.spawn(worker, (firstPort.sendPort, 3));
  await Isolate.spawn(worker, (secondPort.sendPort, 4));
  var first = await firstPort.first;
  var second = await secondPort.first;
  print(first);
  print(second);
}

Example

import 'dart:isolate';

int factorial(int n) {
  var result = 1;
  for (var i = 2; i <= n; i++) {
    result = result * i;
  }
  return result;
}

void worker((SendPort, int) message) {
  var (replyTo, value) = message;
  replyTo.send(factorial(value));
}

Future<void> main() async {
  var firstPort = ReceivePort();
  var secondPort = ReceivePort();
  await Isolate.spawn(worker, (firstPort.sendPort, 5));
  await Isolate.spawn(worker, (secondPort.sendPort, 6));
  var first = await firstPort.first;
  var second = await secondPort.first;
  print('5 factorial: $first');
  print('6 factorial: $second');
}

Key points

  • Isolate.spawn takes a top-level entry function and one message to pass to it.
  • The entry function runs in the new isolate, not in the main isolate.
  • A ReceivePort receives messages, and its SendPort is the address other isolates send to.
  • Ports are the only channel between isolates, because isolates share no memory.
  • A message must be a sendable value, and a record of sendable values is sendable.
  • The main isolate awaits the reply, so the printed result never depends on timing.

In this example, two workers each compute one factorial and send the result back through their own port. The main isolate awaits the first reply and then the second, so 120 prints before 720.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท DartPad

Exercise

How does a spawned worker return its result to the main isolate?