Dart Isolates: Exploring Parallel Processing in Dart - Part 1

Photo by Paul Engel on Unsplash

Dart Isolates: Exploring Parallel Processing in Dart - Part 1

Table of contents

No heading

No headings in the article.

Dart is a client-optimized programming language used for building web, server, desktop, and mobile applications. One of its key features is isolates, which allow you to run a separate instance of your Dart code in a different thread with its own memory heap.

Why Use Isolates in Dart?

The primary advantage of using isolates in Dart is that they allow you to run code concurrently, meaning that you can perform multiple tasks simultaneously. This can greatly improve the performance of your application, especially if you are performing resource-intensive tasks.

Another advantage of isolates is that they allow you to run code in a completely separate thread, meaning that any issues or errors that occur within an isolate will not affect the rest of your application. This makes isolates an ideal solution for running code that is prone to errors or that requires a high level of stability.

How to Use Dart Isolates

To use isolates in Dart, you first need to create an isolate. To do this, you need to use the Isolate class, which provides a method for launching an isolate.

Here's an example of how you might use isolates to perform a resource-intensive task:

import 'dart:isolate';

void main() {
  // Create a new isolate and run the task
  Isolate.spawn(task, null);
}

void task(SendPort sendPort) {
  // Perform a resource-intensive task here
  for (int i = 0; i < 100000000; i++) {
    // ...
  }
}

In this example, the Isolate.spawn method is used to launch a new isolate and run the task function. The task function is run in a separate thread, meaning that it can perform a resource-intensive task without affecting the rest of the application.

Communication between Isolates

While isolates provide a way to run code in separate threads, it's also important to be able to communicate between isolates. Dart provides a SendPort and ReceivePort pair for communication between isolates.

Here's an example of how you might use SendPort and ReceivePort to communicate between isolates:

import 'dart:isolate';

void main() {
  // Create a receive port to receive messages from the isolate
  var receivePort = ReceivePort();

  // Create a new isolate and run the task
  Isolate.spawn(task, receivePort.sendPort);

  // Listen for messages from the isolate
  receivePort.listen((message) {
    print('Received message: $message');
  });
}

void task(SendPort sendPort) {
  // Send a message to the main isolate
  sendPort.send('Hello from the isolate!');
}

In this example, the ReceivePort is used to receive messages from the isolate, while the SendPort is used to send messages to the main isolate. The listen method is used to listen for messages from the isolate, which can then be processed and used as needed.

De-serializing json using isolates

import 'dart:convert';
import 'dart:isolate';

Future<dynamic> parseJson(String jsonString) async {
  // Create a receive port to receive messages from the isolate
  var receivePort = ReceivePort();

  // Define a future to wait for the result from the isolate
  var result = receivePort.first.then((parsedJson) {
    receivePort.close();
    return parsedJson;
  });

  // Create a new isolate and run the task
  Isolate.spawn(jsonParseTask, receivePort.sendPort);

  // Return the future
  return result;
}

void jsonParseTask(SendPort sendPort) {
  // Parse the JSON string
  var parsedJson = json.decode(jsonString);

  // Send the parsed JSON to the main isolate
  sendPort.send(parsedJson);
}

This code defines a new function called parseJson that takes a jsonString as an argument and returns a Future that resolves to the parsed JSON. The function creates a new isolate and runs the jsonParseTask function within it. The jsonParseTask function parses the JSON string and sends the result back to the main isolate, which can access it via the Future returned by parseJson.

This function can be used as follows:

var jsonString = '{"name": "John Doe", "age": 35, "email": "john.doe@example.com"}';

parseJson(jsonString).then((parsedJson) {
  print('Parsed JSON: $parsedJson');
});

Conclusion

Dart isolates provide a powerful way to run code concurrently and improve the performance of your application. By using the Isolate class, SendPort, and ReceivePort, you can easily create and communicate between isolates, allowing you to perform complex and resource-intensive tasks.

The above example shows a basic use case. In Part 2, we will explore isolates in deep along with the latest isolate API changes in flutter 3.7