26

I might have the wrong idea of Isolate and Future. Please help me to clear it up. Here is my understanding of both subjects.

Isolate: Isolates run code in its own event loop, and each event may run smaller tasks in a nested microtask queue.

Future: A Future is used to represent a potential value, or error, that will be available at some time in the future.

My confusions are:

  1. The doc says Isolate has it own loop? I feel like having its own event queue makes more sense to me, am I wrong?

  2. Is future running asynchronously on the main Isolate? I'm assuming future task actually got placed at the end of event queue so if it will be execute by loop in the future. Correct me if I'm wrong.

  3. Why use Isolate when there is future? I saw some examples using Isolate for some heavy task instead of Future. But why? It only makes sense to me when future execute asynchronously on the main isolate queue.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Panda World
  • 1,704
  • 1
  • 20
  • 28
  • 5
    Isolates are like threads. Futures aren't. So if you have expensive computation, a Future will still block the UI but an Isolate won't. – Rémi Rousselet Sep 25 '18 at 12:59

5 Answers5

24

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

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
16

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

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • Is it okay to retrieve data from an isolate without ReceivePort and SendPort? Like for example, storing the obtained data into an already existing variable? – Iván Yoed Apr 20 '21 at 14:58
  • @IvánYoed, I haven't actually tried it, but theoretically it shouldn't work since isolates don't share memory. If you get that to work, though, I'd like to see your example. – Suragch Apr 21 '21 at 01:25
  • 1
    I've recently posted a question regarding this and received a good answer about it. Maybe it is of your interest https://stackoverflow.com/q/67181838/13766744 – Iván Yoed Apr 21 '21 at 03:04
11

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.

CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
4

Isolate could be compared to Thread even if dart is not multithreaded. It has it's own memory and event loop indeed, when Futures shares the same memory

Dart is able to spawn standalone processes, called Isolates (web workers in dart2js), which do not share memory when the main program, but are able to asynchronously, in another process (effectively a thread of sorts) is able to do computations without blocking the main thread.

A Future is run inside the Isolate that called it, not necesserally the main isolate.

I recommend this article which has better explanation than me.

Hadrien Lejard
  • 5,644
  • 2
  • 21
  • 18
0

TLDR: https://medium.com/flutter-community/isolates-in-flutter-a0dd7a18b7f6

Let's understand async-await first and then go into isolates.

void main() async {
  // Read some data.
  final fileData = await _readFileAsync();
  final jsonData = jsonDecode(fileData);

  // Use that data.
  print('Number of JSON keys: ${jsonData.length}');
}

Future<String> _readFileAsync() async {
  final file = File(filename);
  final contents = await file.readAsString();
  return contents.trim();
}

We want to read some data from a file and then decode that JSON and print the JSON Keys length. We don’t need to go into the implementation details here but can take the help of the image below to understand how it works.

enter image description here

When we click on this button Place Bid, it sends a request to _readFileAsync, all of which is dart code that we wrote. But this function _readFileAsync, executes code using Dart Virtual Machine/OS to perform the I/O operation which in itself is a different thread, the I/O thread.

This means, the code in the main function runs inside the main isolate. When the code reaches the _readFileAsync, it transfers the code execution to I/O thread and the Main Isolate waits until the code is completely executed or an error occurs. This is what await keyword does.

enter image description here

Now, once the contents of the files are read, the control returns back to the main isolate and we start parsing the String data as JSON and print the number of keys. This is pretty straight forward. But let’s suppose, the JSON parsing was a very big operation, considering a very huge JSON and we start manipulating the data to conform to our needs. Then this work is happening on the Main Isolate. At this point of time, the UI could hang, making our users fustrated.

Now let's get back to isolates.

Dart uses Isolate model for concurrency. Isolate is nothing but a wrapper around thread. But threads, by definition, can share memory which might be easy for the developer but makes code prone to race conditions and locks. Isolates on the other hand cannot share memory and instead rely on message passing mechanism to talk with each other.

Using isolates, Dart code can perform multiple independent tasks at once, using additional cores if they’re available. Each Isolate has its own memory and a single thread running an event loop.

Hope this help solve someone's doubt.

Dhruvam Sharma
  • 1,661
  • 14
  • 22