Dart:  Concurrency | Using Isolates

Dart: Concurrency | Using Isolates

ยท

3 min read

Introduction:

Dart, known for its simplicity and efficiency, empowers developers with a robust concurrency model through isolates. In this blog post, we'll embark on a hands-on journey, exploring how to effectively use isolates to perform parallel tasks, enhance application responsiveness, and unlock the full potential of Dart's concurrency features.

Getting Started with Isolates: Isolates in Dart are independent units of execution, allowing tasks to run concurrently. The first step in using isolates is to spawn them using the Isolate.spawn function. Let's dive into a simple example.

Example: Basic Usage of Isolates

import 'dart:isolate';

void main() async {
  print('Main isolate starts');

  // Spawning two isolates
  Isolate.spawn(isolateFunction, 'Isolate 1');
  Isolate.spawn(isolateFunction, 'Isolate 2');

  // Performing tasks in the main isolate
  for (int i = 1; i <= 3; i++) {
    print('Main isolate task $i');
    await Future.delayed(Duration(seconds: 1));
  }
}

void isolateFunction(String name) {
  print('$name: Started');

  // Simulating a task in the isolate
  for (int i = 1; i <= 3; i++) {
    print('$name: Task $i');
    sleep(Duration(seconds: 1));
  }

  print('$name: Ends');
}

Explanation:

  • The main function spawns two isolates using Isolate.spawn, each executing the isolateFunction.

  • The main isolate continues to perform tasks concurrently with the spawned isolates.

Communicating Between Isolates: Isolates communicate by passing messages. Dart provides the SendPort and ReceivePort classes for this purpose. Let's see how to send and receive messages between isolates.

Example: Communicating Between Isolates

import 'dart:isolate';

void main() async {
  print('Main isolate starts');

  // Creating a ReceivePort for the main isolate
  final ReceivePort mainReceivePort = ReceivePort();

  // Spawning an isolate and passing the SendPort
  Isolate.spawn(isolateFunction, mainReceivePort.sendPort);

  // Receiving and handling messages from the spawned isolate
  mainReceivePort.listen((message) {
    print('Main isolate received: $message');
  });

  // Sending a message to the spawned isolate
  mainReceivePort.send('Hello from the main isolate');
}

void isolateFunction(SendPort sendPort) {
  print('Spawned isolate started');

  // Creating a ReceivePort for the spawned isolate
  final ReceivePort isolateReceivePort = ReceivePort();

  // Sending the SendPort to the main isolate
  sendPort.send(isolateReceivePort.sendPort);

  // Receiving and handling messages from the main isolate
  isolateReceivePort.listen((message) {
    print('Spawned isolate received: $message');
  });

  // Sending a message to the main isolate
  sendPort.send('Hello from the spawned isolate');
}

Explanation:

  • The main isolate creates a ReceivePort and passes its sendPort to the spawned isolate.

  • The spawned isolate receives the SendPort and establishes communication with the main isolate.

  • Both isolates send and receive messages.

Advanced Usage: Isolate Pools For scenarios involving multiple tasks, Dart provides the IsolatePool class, enabling efficient management of a pool of isolates for parallel execution.

Example: Using Isolate Pools

import 'dart:isolate';

void main() async {
  print('Main isolate starts');

  // Creating an isolate pool with two isolates
  final IsolatePool isolatePool = IsolatePool(2);

  // Submitting tasks to the pool
  isolatePool.run(isolateFunction, 'Task 1');
  isolatePool.run(isolateFunction, 'Task 2');

  // Performing tasks in the main isolate
  for (int i = 1; i <= 3; i++) {
    print('Main isolate task $i');
    await Future.delayed(Duration(seconds: 1));
  }

  // Closing the isolate pool
  await isolatePool.close();
}

void isolateFunction(String task) {
  print('Isolate task "$task" started');

  // Simulating a task in the isolate
  for (int i = 1; i <= 3; i++) {
    print('Isolate task "$task": Step $i');
    sleep(Duration(seconds: 1));
  }

  print('Isolate task "$task" ends');
}

Explanation:

  • The main function creates an IsolatePool with two isolates.

  • Tasks are submitted to the pool using isolatePool.run.

  • The main isolate and isolates in the pool execute tasks concurrently.

Did you find this article valuable?

Support Vinit Mepani (Flutter Developer) by becoming a sponsor. Any amount is appreciated!

ย