On this page22 sections
- Prerequisites
- Connection With Previous Lectures
- Learning Objectives
- 1. Starting a Worker with Isolate.spawn
- 2. One Argument, Many Values
- 3. Many Messages — and Closing the Port
- 4. Two-Way Communication
- 5. A Long-Lived Worker
- 6. Stopping a Worker Cleanly
- 7. Errors in a Spawned Isolate: onError
- 8. Errors from Isolate.run Are Rethrown
- 9. Several Isolates in Parallel
- 10. A Real-World Example
- Code Examples
- Common Beginner Mistakes
- Best Practices
- Mini Challenge
- Practice Questions
- Practice Answers
- Quick Revision
- Key Takeaways
- What's Next?
Lecture 99 — Working with Isolates
| Category | 16 — Concurrency & Isolates |
| Lecture | 099 of 140 |
| Estimated video length | 15 min |
| Target | Dart 3.12.2 |
| Level | Intermediate |
Isolate.runstarts a worker, gets one answer, and throws the worker away. WithIsolate.spawnand ports you keep a worker alive, talk to it in both directions, and give it job after job.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Every output and error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2. Timing lines such as
Parallel: 873 mschange on every run and every computer — read them as "about 1 second".
Prerequisites
Students should already understand, from Lectures 076–098:
- records, destructuring, and list patterns like
var [a, b] = list async/await,try/catch, andFuture.wait(Lectures 089–091)- streams,
await for,.first, andlisten(Lectures 092–096) - isolates,
Isolate.run, and why messages are copied between isolates (Lecture 098)
Connection With Previous Lectures
In Lecture 098 we moved heavy work off the main isolate with one line:
var total = await Isolate.run(() => slowSum(1000000000));That is perfect for one job. But Sara's banking app checks transactions as they arrive. A new isolate per transaction wastes time, and a fresh isolate forgets everything — it cannot keep a running balance. We need a worker that stays alive, receives jobs, answers, and shuts down cleanly.
Learning Objectives
By the end of this lecture you will be able to:
- Start an isolate with
Isolate.spawnand an entry function - Send messages back to the main isolate through a
ReceivePortand itsSendPort - Pass several values into a worker by packing them in a record
- Set up two-way communication by sending a
SendPortback - Build a long-lived worker that handles many jobs
- Close ports and kill isolates so your program always exits
- Catch errors from spawned isolates and from
Isolate.run - Run several isolates in parallel with
Future.wait
1. Starting a Worker with Isolate.spawn
Isolate.spawn starts a new isolate that runs an entry function — a top-level function
with exactly one parameter. The worker cannot return a value to us, so we give it a
SendPort: an address it can send messages to.
import 'dart:isolate';
void addMarks(SendPort replyTo) {
var total = 80 + 75 + 85;
replyTo.send(total);
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(addMarks, port.sendPort);
var total = await port.first;
print('Total from worker: $total');
}Total from worker: 240Analogy — a
ReceivePortis your mailbox and itssendPortis the address written on it. You hand the address to the worker; the worker posts letters, and only you can open the mailbox.
A ReceivePort is a stream of incoming messages. await port.first waits for one
message and then closes the port.
2. One Argument, Many Values
The entry function takes a single argument. To send in data and a reply address, pack them into a record:
import 'dart:isolate';
void averageWorker((List<int>, SendPort) job) {
var (marks, replyTo) = job;
var total = marks.reduce((a, b) => a + b);
replyTo.send(total / marks.length);
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(averageWorker, ([90, 88, 92], port.sendPort));
print('Sara\'s average: ${await port.first}');
}Sara's average: 90.0The list is copied into the worker (Lecture 098).
3. Many Messages — and Closing the Port
A worker can send as many messages as it likes. Agree on a "done" signal (here null) and
close the port when it arrives:
import 'dart:isolate';
void countDown(SendPort replyTo) {
for (var i = 3; i >= 1; i--) {
replyTo.send(i);
}
replyTo.send(null); // "I'm done"
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(countDown, port.sendPort);
await for (var message in port) {
if (message == null) {
port.close();
} else {
print('Received $message');
}
}
print('Port closed, program ends');
}Received 3
Received 2
Received 1
Port closed, program endsAn open ReceivePort in the main isolate keeps the program running. Forget
port.close() and this program never ends — await for waits for mail that never comes.
4. Two-Way Communication
To send jobs to the worker, the worker needs its own mailbox. It creates a
ReceivePort and sends that port's SendPort back — the "handshake". Each job then carries
its own reply address:
import 'dart:isolate';
void doubler(SendPort mainPort) async {
var inbox = ReceivePort();
mainPort.send(inbox.sendPort); // 1. tell main where to send jobs
var (number, replyTo) = await inbox.first as (int, SendPort);
replyTo.send(number * 2); // 3. answer on the reply port
}
void main() async {
var setup = ReceivePort();
await Isolate.spawn(doubler, setup.sendPort);
var workerPort = await setup.first as SendPort;
var reply = ReceivePort();
workerPort.send((21, reply.sendPort)); // 2. a job plus a reply address
print('Answer: ${await reply.first}');
}Answer: 42Messages arrive untyped, so as states what we expect. A fresh reply port per job means
every answer lands in the right place.
5. A Long-Lived Worker
Now the worker uses listen instead of .first, so it keeps answering. A small ask
function hides the reply-port details:
import 'dart:isolate';
void squarer(SendPort mainPort) {
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
inbox.listen((message) {
var (number, replyTo) = message as (int, SendPort);
print('worker: squaring $number');
replyTo.send(number * number);
});
}
Future<int> ask(SendPort worker, int number) async {
var reply = ReceivePort();
worker.send((number, reply.sendPort));
return await reply.first as int;
}
void main() async {
var setup = ReceivePort();
var isolate = await Isolate.spawn(squarer, setup.sendPort);
var worker = await setup.first as SendPort;
for (var n in [2, 3, 4]) {
print('$n squared is ${await ask(worker, n)}');
}
isolate.kill();
}worker: squaring 2
2 squared is 4
worker: squaring 3
3 squared is 9
worker: squaring 4
4 squared is 16One isolate, three jobs. Isolate.spawn returns an Isolate; isolate.kill() shuts the
worker down.
6. Stopping a Worker Cleanly
kill stops a worker from outside. The polite way is a "stop" message: the worker closes
its inbox, has nothing left to do, and exits. onExit tells us when it is gone:
import 'dart:isolate';
void squarer(SendPort mainPort) {
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
inbox.listen((message) {
if (message == 'stop') {
print('worker: closing my inbox');
inbox.close();
return;
}
var (number, replyTo) = message as (int, SendPort);
replyTo.send(number * number);
});
}
void main() async {
var setup = ReceivePort();
var exit = ReceivePort();
await Isolate.spawn(squarer, setup.sendPort, onExit: exit.sendPort);
var worker = await setup.first as SendPort;
var reply = ReceivePort();
worker.send((5, reply.sendPort));
print('5 squared is ${await reply.first}');
worker.send('stop');
await exit.first;
print('Worker has exited');
}5 squared is 25
worker: closing my inbox
Worker has exitedWhen the worker exits, its onExit port receives null. A worker busy in a loop never reads
its messages; stop it with isolate.kill(priority: Isolate.immediate) (Example 5). Workers
still alive when the main isolate finishes are shut down with it.
7. Errors in a Spawned Isolate: onError
An uncaught error in a spawned isolate kills that isolate — and the main isolate is not
told unless it asks. Pass an onError port: each error arrives as a two-item list, the
message and the stack trace, both as strings.
import 'dart:isolate';
void checkMarks(int marks) {
if (marks > 100) {
throw ArgumentError('Marks cannot be above 100: $marks');
}
print('worker: $marks is fine');
}
void main() async {
var errors = ReceivePort();
var exit = ReceivePort();
await Isolate.spawn(
checkMarks,
120,
onError: errors.sendPort,
onExit: exit.sendPort,
);
var [message, _] = await errors.first as List;
print('Worker failed: $message');
await exit.first;
print('Worker is gone, main carries on');
}Worker failed: Invalid argument(s): Marks cannot be above 100: 120
Worker is gone, main carries onThe error is only text now — you cannot catch it with on ArgumentError.
8. Errors from Isolate.run Are Rethrown
Isolate.run does all of this for you: if the function throws, the same error is thrown
again from the await, so an ordinary try/catch works:
import 'dart:isolate';
double average(List<int> marks) {
if (marks.isEmpty) throw StateError('No marks to average');
return marks.reduce((a, b) => a + b) / marks.length;
}
void main() async {
try {
var result = await Isolate.run(() => average([]));
print(result);
} on StateError catch (e) {
print('Caught in main: ${e.message}');
}
}Caught in main: No marks to averagePrefer Isolate.run for one-off jobs; keep Isolate.spawn for long-lived workers.
9. Several Isolates in Parallel
Each isolate can run on its own CPU core. Isolate.run returns a future, so Future.wait
from Lecture 091 runs several of them at the same time:
import 'dart:isolate';
int slowSum(int limit) {
var sum = 0;
for (var i = 0; i < limit; i++) {
sum += i % 7;
}
return sum;
}
void main() async {
const limit = 1000000000;
var stopwatch = Stopwatch()..start();
slowSum(limit);
slowSum(limit);
slowSum(limit);
print('Sequential: ${stopwatch.elapsedMilliseconds} ms');
stopwatch.reset();
var sums = await Future.wait([
Isolate.run(() => slowSum(limit)),
Isolate.run(() => slowSum(limit)),
Isolate.run(() => slowSum(limit)),
]);
print('Parallel: ${stopwatch.elapsedMilliseconds} ms');
print(sums);
}Sequential: 3105 ms
Parallel: 873 ms
[2999999997, 2999999997, 2999999997]Three sums in about the time of one — as long as your computer has spare CPU cores.
10. A Real-World Example
A long-lived worker builds student reports. Three requests go out together; then the worker is stopped cleanly:
import 'dart:isolate';
void reportWorker(SendPort mainPort) {
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
inbox.listen((message) {
if (message == 'stop') {
inbox.close();
return;
}
var (name, marks, replyTo) = message as (String, List<int>, SendPort);
var total = marks.reduce((a, b) => a + b);
replyTo.send('$name: total $total, average ${total / marks.length}');
});
}
Future<String> askReport(SendPort worker, String name, List<int> marks) async {
var reply = ReceivePort();
worker.send((name, marks, reply.sendPort));
return await reply.first as String;
}
void main() async {
var setup = ReceivePort();
var exit = ReceivePort();
await Isolate.spawn(reportWorker, setup.sendPort, onExit: exit.sendPort);
var worker = await setup.first as SendPort;
var reports = await Future.wait([
askReport(worker, 'Ali', [80, 75, 85]),
askReport(worker, 'Sara', [90, 88, 92]),
askReport(worker, 'Zayan', [70, 65, 72]),
]);
reports.forEach(print);
worker.send('stop');
await exit.first;
print('Report worker stopped');
}Ali: total 240, average 80.0
Sara: total 270, average 90.0
Zayan: total 207, average 69.0
Report worker stoppedHandshake, reply ports, a stop message, and onExit — a worker's whole lifecycle.
Code Examples
Example 1 — One Message Back
import 'dart:isolate';
void greet(SendPort replyTo) {
replyTo.send('Hello from another isolate!');
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(greet, port.sendPort);
print(await port.first);
}Hello from another isolate!Example 2 — Data In, Answer Out
import 'dart:isolate';
void sumWorker((List<int>, SendPort) job) {
var (numbers, replyTo) = job;
replyTo.send(numbers.reduce((a, b) => a + b));
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(sumWorker, ([4, 5, 6], port.sendPort));
print('Sum: ${await port.first}');
}Sum: 15Example 3 — A Stream of Names
import 'dart:isolate';
void names(SendPort replyTo) {
for (var name in ['Ali', 'Sara', 'Zayan']) {
replyTo.send(name);
}
replyTo.send(null);
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(names, port.sendPort);
await for (var name in port) {
if (name == null) break;
print('Hello, $name');
}
}Hello, Ali
Hello, Sara
Hello, Zayanbreak cancels the await for subscription, which also closes the port.
Example 4 — The Handshake
import 'dart:isolate';
void shouter(SendPort mainPort) async {
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
var (text, replyTo) = await inbox.first as (String, SendPort);
replyTo.send(text.toUpperCase());
}
void main() async {
var setup = ReceivePort();
await Isolate.spawn(shouter, setup.sendPort);
var worker = await setup.first as SendPort;
var reply = ReceivePort();
worker.send(('hello sara', reply.sendPort));
print(await reply.first);
}HELLO SARAExample 5 — Killing a Busy Worker
import 'dart:isolate';
void forever(String name) async {
while (true) {
print('$name is still working...');
await Future.delayed(Duration(milliseconds: 400));
}
}
void main() async {
var exit = ReceivePort();
var isolate = await Isolate.spawn(forever, 'Zayan', onExit: exit.sendPort);
await Future.delayed(Duration(seconds: 1));
isolate.kill(priority: Isolate.immediate);
await exit.first;
print('Worker killed');
}Zayan is still working...
Zayan is still working...
Zayan is still working...
Worker killedExample 6 — Catching an Isolate.run Error
import 'dart:isolate';
void main() async {
try {
await Isolate.run(() => int.parse('abc'));
} on FormatException catch (e) {
print('Caught: ${e.message}');
}
}Caught: Invalid radix-10 numberExample 7 — Student Averages in Parallel
import 'dart:isolate';
double average(List<int> marks) => marks.reduce((a, b) => a + b) / marks.length;
void main() async {
var averages = await Future.wait([
Isolate.run(() => average([80, 75, 85])),
Isolate.run(() => average([90, 88, 92])),
Isolate.run(() => average([70, 65, 72])),
]);
print('Averages: $averages');
}Averages: [80.0, 90.0, 69.0]Example 8 — Shopping Total
import 'dart:isolate';
void cartWorker((Map<String, double>, SendPort) job) {
var (cart, replyTo) = job;
var total = cart.values.fold(0.0, (sum, price) => sum + price);
replyTo.send(total);
}
void main() async {
var port = ReceivePort();
var cart = {'Notebook': 500.0, 'Pen': 50.0, 'Bag': 1500.0};
await Isolate.spawn(cartWorker, (cart, port.sendPort));
print('Total: ${await port.first}');
}Total: 2050.0Example 9 — A Bank Worker That Remembers
import 'dart:isolate';
void bankWorker(SendPort mainPort) {
var balance = 1000.0; // lives as long as the worker
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
inbox.listen((message) {
var (amount, replyTo) = message as (double, SendPort);
balance += amount;
replyTo.send(balance);
});
}
Future<double> apply(SendPort worker, double amount) async {
var reply = ReceivePort();
worker.send((amount, reply.sendPort));
return await reply.first as double;
}
void main() async {
var setup = ReceivePort();
var isolate = await Isolate.spawn(bankWorker, setup.sendPort);
var worker = await setup.first as SendPort;
for (var amount in [-250.0, 500.0, -100.0]) {
print('After $amount: ${await apply(worker, amount)}');
}
isolate.kill();
}After -250.0: 750.0
After 500.0: 1250.0
After -100.0: 1150.0Isolate.run could never do this: each call starts from scratch.
Example 10 — A Faulty Temperature Sensor
import 'dart:isolate';
void sensor(double reading) {
if (reading < -273.15) throw StateError('Impossible reading: $reading');
print('Reading OK: $reading');
}
void main() async {
var errors = ReceivePort();
var exit = ReceivePort();
await Isolate.spawn(
sensor,
-300.0,
onError: errors.sendPort,
onExit: exit.sendPort,
);
var [message, _] = await errors.first as List;
print('Sensor error: $message');
await exit.first;
}Sensor error: Bad state: Impossible reading: -300.0Common Beginner Mistakes
1. Never closing a ReceivePort
void main() async {
var port = ReceivePort();
await Isolate.spawn(work, port.sendPort); // work sends 42
port.listen((m) => print('Got $m'));
// ✗ the port stays open
}Got 42No error — the program just never ends (stop it with Ctrl+C). Close the port after the
last message, or use .first, which closes it for you.
2. Reading the same ReceivePort twice
void main() async {
var port = ReceivePort();
await Isolate.spawn(work, port.sendPort); // work sends 1, then 2
print(await port.first);
// print(await port.first); // ✗
}Bad state: Stream has already been listened to.A ReceivePort is a single-subscription stream, and .first already used it. Use one
await for for many messages, or a reply port per job (Step 5).
3. An entry function with two parameters
void add(int a, int b) => print(a + b);
void main() async {
// await Isolate.spawn(add, 2); // ✗
}Error: The argument type 'void Function(int, int)' can't be assigned to the parameter type 'void Function(int)'.The entry function takes exactly one argument. Pack several values into a record (Step 2).
4. Waiting for an answer from a worker that crashed
void boom(SendPort replyTo) => throw StateError('bad');
void main() async {
var port = ReceivePort();
await Isolate.spawn(boom, port.sendPort);
// var result = await port.first; // ✗ waits forever
}Unhandled exception:
Bad state: badThe worker dies, but main waits forever for its reply. Pass onError and onExit ports
(Step 7), or use Isolate.run.
Best Practices
- Use
Isolate.runfor one job; useIsolate.spawnwhen a worker should stay alive or remember state. - Give each job its own reply port.
- Close every
ReceivePortyou create —.firstandbreakdo it for you. - Stop workers with a "stop" message,
kill(), orkill(priority: Isolate.immediate), and useonExitto know when they are gone. - Always pass
onErrortoIsolate.spawnwhen main waits for a worker's answer. - Run independent isolates together with
Future.wait, but no more than you have CPU cores.
Mini Challenge
Zayan's weather station needs a long-lived converter worker. Send it the Celsius readings
25.0, 30.0, and -5.0 one at a time, print each Fahrenheit answer
(celsius * 9 / 5 + 32), then send 'stop' and wait for the worker to exit.
Try it yourself before opening the solution.
Show solution
import 'dart:isolate';
void converter(SendPort mainPort) {
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
inbox.listen((message) {
if (message == 'stop') {
inbox.close();
return;
}
var (celsius, replyTo) = message as (double, SendPort);
replyTo.send(celsius * 9 / 5 + 32);
});
}
Future<double> convert(SendPort worker, double celsius) async {
var reply = ReceivePort();
worker.send((celsius, reply.sendPort));
return await reply.first as double;
}
void main() async {
var setup = ReceivePort();
var exit = ReceivePort();
await Isolate.spawn(converter, setup.sendPort, onExit: exit.sendPort);
var worker = await setup.first as SendPort;
for (var c in [25.0, 30.0, -5.0]) {
print('$c°C = ${await convert(worker, c)}°F');
}
worker.send('stop');
await exit.first;
print('Converter stopped');
}25.0°C = 77.0°F
30.0°C = 86.0°F
-5.0°C = 23.0°F
Converter stoppedPractice Questions
Solve each one before looking at the answers.
Beginner
- Spawn a worker that sends back the text
'Ready', and print it. - Spawn a worker with the record
(10, port.sendPort)that sends back the number times 3. - Use
Isolate.runto add the numbers 1 to 100 and print the result.
Application
-
A worker sends
'A','B','C', thennull. Print each letter withawait forand make sure the program ends. -
Why does this crash, and how would you fix it?
var port = ReceivePort(); await Isolate.spawn(work, port.sendPort); print(await port.first); print(await port.first); -
Use a handshake so main sends
'Sara'to the worker and the worker replies'Welcome, Sara!'. -
Run
() => throw Exception('Disk full')withIsolate.runand printCaught:plus the error.
Challenge
- Build a long-lived counter worker that keeps a running total. Send
10,20,30and print10,30,60; then stop it with'stop'and wait foronExit. - With
Future.waitandIsolate.run, compute the sum of1..nforn= 10, 100, 1000, and 10000 in parallel and print the list. - Spawn a worker that throws
StateError('Negative balance')when given-50.0. Catch it throughonError, printWorker failed: ..., then printDoneafter the worker exits.
Practice Answers
Question 1 — Solution
import 'dart:isolate';
void ready(SendPort replyTo) => replyTo.send('Ready');
void main() async {
var port = ReceivePort();
await Isolate.spawn(ready, port.sendPort);
print(await port.first);
}ReadyQuestion 2 — Solution
import 'dart:isolate';
void triple((int, SendPort) job) {
var (number, replyTo) = job;
replyTo.send(number * 3);
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(triple, (10, port.sendPort));
print(await port.first);
}30Question 3 — Solution
import 'dart:isolate';
void main() async {
var sum = await Isolate.run(
() => List.generate(100, (i) => i + 1).reduce((a, b) => a + b),
);
print(sum);
}5050Question 4 — Solution
import 'dart:isolate';
void letters(SendPort replyTo) {
for (var letter in ['A', 'B', 'C']) {
replyTo.send(letter);
}
replyTo.send(null);
}
void main() async {
var port = ReceivePort();
await Isolate.spawn(letters, port.sendPort);
await for (var letter in port) {
if (letter == null) break;
print(letter);
}
}A
B
CQuestion 5 — Solution
The first .first already listened to the port (and closed it), so the second throws
Bad state: Stream has already been listened to. Read both with one await for, closing
the port after the second.
Question 6 — Solution
import 'dart:isolate';
void welcomer(SendPort mainPort) async {
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
var (name, replyTo) = await inbox.first as (String, SendPort);
replyTo.send('Welcome, $name!');
}
void main() async {
var setup = ReceivePort();
await Isolate.spawn(welcomer, setup.sendPort);
var worker = await setup.first as SendPort;
var reply = ReceivePort();
worker.send(('Sara', reply.sendPort));
print(await reply.first);
}Welcome, Sara!Question 7 — Solution
import 'dart:isolate';
void main() async {
try {
await Isolate.run(() => throw Exception('Disk full'));
} catch (e) {
print('Caught: $e');
}
}Caught: Exception: Disk fullQuestion 8 — Solution
import 'dart:isolate';
void counter(SendPort mainPort) {
var total = 0;
var inbox = ReceivePort();
mainPort.send(inbox.sendPort);
inbox.listen((message) {
if (message == 'stop') {
inbox.close();
return;
}
var (amount, replyTo) = message as (int, SendPort);
total += amount;
replyTo.send(total);
});
}
Future<int> add(SendPort worker, int amount) async {
var reply = ReceivePort();
worker.send((amount, reply.sendPort));
return await reply.first as int;
}
void main() async {
var setup = ReceivePort();
var exit = ReceivePort();
await Isolate.spawn(counter, setup.sendPort, onExit: exit.sendPort);
var worker = await setup.first as SendPort;
for (var n in [10, 20, 30]) {
print(await add(worker, n));
}
worker.send('stop');
await exit.first;
}10
30
60Question 9 — Solution
import 'dart:isolate';
int sumTo(int n) {
var total = 0;
for (var i = 1; i <= n; i++) {
total += i;
}
return total;
}
void main() async {
var sums = await Future.wait([
for (var n in [10, 100, 1000, 10000]) Isolate.run(() => sumTo(n)),
]);
print(sums);
}[55, 5050, 500500, 50005000]Question 10 — Solution
import 'dart:isolate';
void withdraw(double amount) {
if (amount < 0) throw StateError('Negative balance');
print('Withdrew $amount');
}
void main() async {
var errors = ReceivePort();
var exit = ReceivePort();
await Isolate.spawn(
withdraw,
-50.0,
onError: errors.sendPort,
onExit: exit.sendPort,
);
var [message, _] = await errors.first as List;
print('Worker failed: $message');
await exit.first;
print('Done');
}Worker failed: Bad state: Negative balance
DoneQuick Revision
- How many parameters does an entry function for
Isolate.spawntake? - What is the difference between a
ReceivePortand aSendPort? - Why does an open
ReceivePortkeep a program running? - How does a worker let main send it jobs?
- Name two ways to stop a long-lived worker.
- What does the
onExitport receive? - How does an error from
Isolate.spawnreach main, compared withIsolate.run? - When does running isolates with
Future.waitmake a program faster?
Key Takeaways
Isolate.spawn(entry, argument)starts a worker; the entry function takes one argument.- A
ReceivePortis a stream of messages; itssendPortis the address other isolates send to. - Pack data and a reply
SendPortinto a record to send several values. - Two-way communication: the worker sends its own
SendPortback in a handshake. - A worker that
listens keeps handling jobs and can remember state between them. - Close ports, send
'stop', orkill()a worker;onExittells you when it is gone. - Spawned errors arrive as text on the
onErrorport;Isolate.runrethrows the real error. Future.waitover severalIsolate.runcalls uses several CPU cores at once.
What's Next?
Lecture 100 — Concurrency Best Practices. You now have every tool: futures, streams,
Isolate.run, and long-lived workers. Next we learn which one to pick for each job and
how to keep the main isolate responsive.