DEV Community

Mostafa Ead
Mostafa Ead

Posted on

Understanding Concurrency in Dart: A Deep Dive

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");
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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!');
}
Enter fullscreen mode Exit fullscreen mode

Communication Between Isolates

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

// Code for sending and receiving messages 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');
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)