Dart: Concurrency | Using Isolates

Vinit MepaniVinit Mepani
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.

0
Subscribe to my newsletter

Read articles from Vinit Mepani directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vinit Mepani
Vinit Mepani

"Hello World, I'm Vinit Mepani, a coding virtuoso driven by passion, fueled by curiosity, and always poised to conquer challenges. Picture me as a digital explorer, navigating through the vast realms of code, forever in pursuit of innovation. In the enchanting kingdom of algorithms and syntax, I wield my keyboard as a magical wand, casting spells of logic and crafting solutions to digital enigmas. With each line of code, I embark on an odyssey of learning, embracing the ever-evolving landscape of technology. Eager to decode the secrets of the programming universe, I see challenges not as obstacles but as thrilling quests, opportunities to push boundaries and uncover new dimensions in the realm of possibilities. In this symphony of zeros and ones, I am Vinit Mepani, a coder by passion, an adventurer in the digital wilderness, and a seeker of knowledge in the enchanting world of code. Join me on this quest, and let's create digital wonders together!"