Dart Isolates

Summary: in this tutorial, you’ll learn about Dart isolates and how they work.

Introduction to Dart Isolates #

When you launch a program, the computer creates a new process. A process has its own memory space and resources. In other words, a process is an instance of the program.

By default, programs cannot access data in other programs, and processes cannot access data from other processes. They are isolated from each other.

You use inter-process communication (IPC) to allow processes to communicate with others.

For example, when you open a web browser, you start a process on your computer.

A thread is a unit execution within a process. By default, a process has a central thread. If a program has a single thread, it is a single-threaded program. A program with more than one thread is a multi-threaded program.

A web browser with multiple tabs creates multiple threads within a process.

Unlike processes, threads can share memory and resources within a process since all threads share the same memory; this allows fast communication but requires careful synchronization, such as locks.

Dart uses something called isolates to enable non-blocking, concurrent programming without the pitfalls of shared memory concurrency.

An isolate has its memory heap and thread of execution. Unlike threads, isolates do not share memory. Instead, they communicate with each other via passing messages.

You can think of isolates as threads with walls around them. In other words, an isolate is a safe, sandboxed thread communicating via messages instead of touching shared data.

Isolates make single-threaded UI frameworks like Flutter excellent because they prevent one part of the app from breaking another due to shared state issues.

Dart Isolate example #

Here’s a simple program to show how to create a new isolate:

import 'dart:isolate';

void main() {
  final receivePort = ReceivePort();

  Isolate.spawn(task, receivePort.sendPort);

  print("Main: waiting for isolate...");

  receivePort.listen((message) {
    print("Main: Got message from isolate: $message");
    receivePort.close();
  });
}

void task(SendPort sendPort) {
  print("Isolate: doing work...");
  final result = 1 + 1;
  sendPort.send("Result is $result");
}Code language: Dart (dart)

How it works.

First, import the dart:isolate package:

import 'dart:isolate';Code language: Dart (dart)

Second, open a receive port in the main isolate:

final receivePort = ReceivePort();Code language: Dart (dart)

Third, create an isolate with the receive port from the main isolate:

Isolate.spawn(callback, receivePort.sendPort);Code language: Dart (dart)

The task is the callback executed in the new isolate.

Fourth, listen for the message from the main isolate and close the port after receiving:

receivePort.listen((message) {
    print("Main: Got message from isolate: $message");
    receivePort.close();
});Code language: Dart (dart)

Finally, execute the callback (task) in the isolate and send a message to the main isolate using the SendPort:

void task(SendPort sendPort) {
  print("Isolate: doing work...");
  final result = 2 + 2; // Synchronous computation
  sendPort.send("Result is $result");
}Code language: Dart (dart)

Summary #

  • Isolates are essentially threads without shared memory.
Was this tutorial helpful ?