Beginner · Async Dart and packages · topic 11 of 50 · 25 min
Isolates for heavy work
Explanation
Waiting versus working
There are two kinds of slow. Waiting (for a network or a file) uses no CPU; async/await handles it perfectly on one thread. Working (calculating, parsing, compressing) uses the CPU continuously. While the main isolate is busy working, it cannot draw frames or respond to taps.
Flutter aims to draw a new frame about every 16 milliseconds (60 frames per second; even faster on 90 or 120 Hz screens). If one piece of work takes 200 ms on the main isolate, about a dozen frames are missed and the user sees the app stutter, called jank.
What is an isolate?
An isolate is Dart's unit of concurrency: an independent worker with its own memory and its own event loop. Isolates do not share memory, so there are no data races between them; they communicate by sending messages (copies of data). Your app's code normally runs on the main isolate.
Isolate.run
import 'dart:convert';
import 'dart:isolate';
List<dynamic> parseHugeJson(String text) => jsonDecode(text) as List<dynamic>;
Future<void> main() async {
final bigText = '[${List.filled(200000, '{"id":1,"name":"item"}').join(',')}]';
final items = await Isolate.run(() => parseHugeJson(bigText)); // runs on a new isolate
print('Parsed ${items.length} items'); // Parsed 200000 items
}In Flutter you will also see compute(function, argument) from the foundation library, which does the same job and also works on the web (where it runs on the main thread, because the web does not support isolates in the same way).
When do you need it?
| Task | Isolate needed? |
|---|---|
| Calling an API with http | No: it is waiting, async is enough |
| Parsing a small JSON response (a few KB) | No: it is fast |
| Parsing a multi-megabyte JSON file | Often yes |
| Resizing or filtering a photo in Dart | Yes |
| Searching or sorting tens of thousands of items | Maybe: measure first |
Rules of thumb
- Measure first with Flutter DevTools (module 9). Do not move everything into isolates "just in case".
- The function you run must be self-contained: it gets its input as an argument (copied) and returns a result (copied). It cannot touch your widgets or state.
- Sending very large objects between isolates costs copying time; send what you need.
Common mistakes
- Using isolates for network calls: unnecessary; they are already asynchronous.
- Trying to update UI or global state from inside the isolate function: it has its own memory.
- Expecting isolates to speed up small work: starting one has a cost.
- Blocking the UI with a long synchronous loop and blaming Flutter. Move the loop to an isolate.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Isolates for heavy work · 1/6
Waiting is handled by async. Heavy working, like parsing a huge file, still blocks the main isolate.
Prefer a video by a teacher? Find free videos on “dart isolates isolate.run flutter compute jank heavy work” on YouTube ↗
In real life: Importing a large product catalogue
A wholesale distributor's app downloads a 15 MB JSON catalogue of 80,000 products each morning. Parsing it on the main isolate froze the screen for two seconds. Moving jsonDecode and the mapping into Isolate.run keeps the progress animation smooth, and the parsed list comes back ready to save in the local database.
import 'dart:isolate';
Future<int> countExpensive(List<int> prices) {
return Isolate.run(() => prices.where((p) => p > 1000).length);
}
Future<void> main() async {
final prices = List.generate(500000, (i) => i % 2000);
print(await countExpensive(prices)); // 249750
}Practice (0/3 done)
Which task most needs an isolate?
Why can an isolate function not change your widget's state directly?
Write a function that counts the prime numbers below 3,000,000 with a simple loop. Time it on the main isolate, then run it with Isolate.run and time it again while a periodic Timer prints "tick" every 100 ms. Note what happens to the ticks in each case.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Packages and pubAsync Dart and packages · same module
- Interview questions: DartFlutter careers and interviews
- async and await: waiting without blockingC# and .NET · Exceptions, delegates, events and async
- async and awaitJavaScript Programming (language in depth) · Asynchronous JavaScript
- Async Rust with tokioRust Programming · Concurrency and async
- async/await and error handlingFrontend Web Development · Async JavaScript, modules and tools
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is jank?
Answer: Visible stutter caused by missed frames
Long main-isolate work causes it.
How do isolates communicate?
Answer: Messages (copied data)
They have separate memory.
Which API runs one function on a new isolate and returns its result?
Answer: Isolate.run
Available since Dart 2.19.
Does an http.get call need an isolate?
Answer: No; it is asynchronous waiting, not CPU work
async handles waiting.
What does an isolate NOT share with other isolates?Related
What kind of work benefits most from async/await?Related
Answer: Waiting for network, disk or database (I/O)
async frees threads during I/O waits.
What does an async function return?Related
async function f() { return 3; } What is f()?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 1 more topic in “Async Dart and packages” before its exam: Packages and pub.
- Module 3 exam: Async Dart and packages · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Flutter setup and your first app. 50 topics left in the course before the final exam.