Understanding Concurrency in Dart: A Deep Dive

Mostafa Ead
2 min readOct 15, 2023

--

Introduction

Concurrency is a fundamental aspect of modern software development, enabling applications to perform multiple tasks simultaneously. Dart, the language behind the popular Flutter framework, offers robust support for concurrent programming. In this post, we’ll explore how Dart handles concurrency, focusing on its unique `Isolate` model.

Async/Await: The Basics

Before diving into isolates, it’s essential to understand Dart’s `async/await` syntax. This feature allows you to write asynchronous code that looks almost like synchronous code. Here’s a quick example:

Future<void> fetchData() async {
var data = await someAsyncFunction();
print("Data fetched: $data");
}

The `await` keyword pauses the function’s execution until `someAsyncFunction()` completes, allowing other tasks to run in the meantime.

Future and Stream: Asynchronous Data Types

Dart uses `Future` and `Stream` objects to represent values that will be provided in the future. A `Future` is like a promise that will eventually complete with a value or an error. A `Stream` is similar but can provide multiple values over time.

Future<int> fetchInt() async {
return 42;
}

Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
yield i;
}
}

Isolates: Dart’s Concurrency Model

Now, let’s talk about the star of the show: Isolates. Unlike traditional shared-memory threads, each Dart isolate has its own memory heap and runs in its own thread. This design eliminates many complexities associated with shared-state concurrency, such as data races and deadlocks.

Creating an Isolate

Here’s how you can create a new isolate:

import 'dart:isolate';
void foo(var message) {
print('Isolate received: $message');
}

void main() {
Isolate.spawn(foo, 'Hello, Isolate!');
}

Communication Between Isolates

Isolates communicate with each other using message passing. You can send simple data types like numbers, strings, and lists between isolates.

import 'dart:isolate';
void newIsolate(SendPort mainSendPort) {
ReceivePort newIsolateReceivePort = ReceivePort();
mainSendPort.send(newIsolateReceivePort.sendPort);
newIsolateReceivePort.listen((message) {
print('Message received in new isolate: $message');
});
}

void main() async {
ReceivePort mainReceivePort = ReceivePort();
Isolate.spawn(newIsolate, mainReceivePort.sendPort);
SendPort? newIsolateSendPort = await mainReceivePort.first;
newIsolateSendPort?.send('Hello from main isolate');
}

Conclusion

Dart’s approach to concurrency, especially its use of isolates, offers a robust and straightforward way to write concurrent programs. Whether you’re building a CPU-intensive computation or a responsive UI, Dart has got you covered.

--

--