Flutter Isolate vs Future

In one sentence we could say,

Isolates: Dart is single-threaded but it is capable of doing multi-threading stuff using Isolates (many processes).

Future: Future is a result which is returned when dart has finished an asynchronous work. The work is generally done in that single-thread.


A Future is a handle that allows you to get notified when async execution is completed. Async execution uses the event queue and code is executed concurrently within the same thread.

https://webdev.dartlang.org/articles/performance/event-loop

Dart code is by default executed in the root isolate.

You can start up additional isolates that usually run on another thread. An isolate can be either loaded from the same Dart code the root isolate was started with (with a different entry-point than main() https://api.dartlang.org/stable/2.0.0/dart-isolate/Isolate/spawn.html) or with different Dart code (loaded from some Dart file or URL https://api.dartlang.org/stable/2.0.0/dart-isolate/Isolate/spawnUri.html).

Isolates don't share any state and can only communicate using message passing (SendPort/ReceivePort). Each isolate has its own event queue.

https://webdev.dartlang.org/articles/performance/event-loop


An Isolate runs Dart code on a single thread. Synchronous code like

print('hello');

is run immediately and can't be interrupted.

An Isolate also has an Event Loop that it uses to schedule asynchronous tasks on. Asynchronous doesn't mean that these tasks are run on a separate thread. They are still run on the same thread. Asynchronous just means that they are scheduled for later.

The Event Loop runs the tasks that are scheduled in what is called an Event Queue. You can put a task in the Event Queue by creating a future like this:

Future(() => print(hello));

The print(hello) task will get run when the other tasks ahead of it in the Event Queue have finished. All of this is happening on the same thread, that is, the same Isolate.

Some tasks don't get added to the Event Queue right away, for example

Future.delayed(Duration(seconds: 1), () => print('hello'));

which only gets added to the queue after a delay of one second.

So far everything I've been talking about gets done on the same thread, the same Isolate. Some work may actually get done on a different thread, though, like IO operations. The underlying framework takes care of that. If something expensive like reading from disk were done on the main Isolate thread then it would block the app until it finished. When the IO operation finishes the future completes and the update with the result is added to the Event Queue.

When you need to do CPU intensive operations yourself, you should run them on another isolate so that it doesn't cause jank in your app. The compute property is good for this. You still use a future, but this time the future is returning the result from a different Isolate.

Further study

  • Futures - Isolates - Event Loop
  • Dart asynchronous programming: Isolates and event loops
  • Are Futures in Dart threads?
  • The Event Loop and Dart
  • Flutter/Dart non-blocking demystify
  • The Engine architecture
  • Single Thread Dart, What? — Part 1
  • Single Thread Dart, What? — Part 2
  • Flutter Threading: Isolates, Future, Async And Await
  • The Fundamentals of Zones, Microtasks and Event Loops in the Dart Programming Language
  • An introduction to the dart:io library
  • What thread / isolate does flutter run IO operations on?