Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I am having a problem with Flutter/Dart Async code execution, as in how does it work

Tags:

flutter

dart

In Flutter we use async await and Future, can someone explain that if we don't use another thread (which we can't in dart) and run the job on main UIThread only won't the app become choppy because even if we are waiting for the job to execute it will ultimately execute on UIThread only. I somewhere read about isolates also. But cannot paint the exact picture. If someone can explain in detail.

like image 401
Yash Sharma Avatar asked Jan 01 '23 04:01

Yash Sharma


1 Answers

I think you missed something when it comes to asynchronous methods in Dart. Dart is a single-threaded programming language, Java or C# are multi-threaded programming languages, forget async as a new thread, it doesn't happen in Dart. Dart is a single-threaded programming language. This means is that Dart can only run one instruction at a time, while Java could run multiple instructions concurrently.

As a rule, everything you do in Dart will start in UI-Thread. Whatever method you call in Dart, whether using sync, async, then, they will be running on UI-Thread, since Dart is a single thread. In single-threaded languages ​​like Javascript and Dart, an async method is NOT executed in parallel but following the regular sequence of events, handled by the Event Loop. There are some problems (I would give some approaches, as we will see below) if you run the following code in a multithreaded language where fetch will take some time to execute:

String user = new Database.fetch(David);
String personalData = new Database.fetch(user);

You will receive David's data in user, and after that, you will receive your data. This will lock your UI, unlike languages ​​like Java which have Threads, where you can perform this task in the background, on another thread, and the UI-Thread will run smoothly.

If you do this at Dart

String user = new Database.fetch(David);
String personalData = new Database.fetch(user);

user will be null in personalData, because the fetch event is a Future.

How to solve this in Dart?

String user = await Database.fetch(David);
String personalData = await Database.fetch(user);

For those who like a more functional paradigm (I don't like it) you can use then.

Database.fetch(David).then((user){
Database.fetch(user).then((personal){
String personalData = personal;
});
});

However, imagine that you have billions of data in that database, this heavy task will probably cause the animations on your screen to freeze, and you will see a jank in the user's UI, for that purpose isolates were invented.

Dart Isolates give you a way to perform real multi-threading in Dart. They have their own separate heaps(memory), and run the code in the background, just like the Threads of multi-threaded languages. I could explain how isolates work, but it would make this response very long, and the goal is just to differentiate asynchronous from multi-threaded methods.

A simple way to solve the problem above using isolates would be using compute.

Compute was created to facilitate the creation of isolates, you just pass the function and the data that this function will execute, and that's it! Important to remember that compute is a Future, so you have to use await or then to get its result.

In our example, we could create a new thread and get its result when we finish by just calling compute like this:

String user = await compute(Database.fetch,David);
String personalData = await compute(Database.fetch,user);

Very simple, isn't it?

In summary: Everything that waits some time to be completed, in Dart is called a "Future". To wait for the result of a future to be assigned to a variable, use await or then. The asynchronous methods (await and then) can be used to obtain a result from a Future, and are executed ON THE MAIN THREAD because Dart is single-thread. If you want to run any function on a new thread, you can create an isolate. Dart offers an easy-to-use isolate wrapper called compute, where you only need to pass one method that will be processed and the data that will be processed, and it will return its result in the future.

  • NOTE: if you are going to use compute make sure you are using a static or top-level method (see that in the example I used Database.fetch it was no accident if you need to call Database().fetch or need to create an instance of it, means it is not a static method and will not work with isolates).

English is not my first language and I didn't want to write so much because of that, but I hope I helped differentiate between multi-threaded asynchronous programming from single-threaded asynchronous programming.

like image 174
jonatas Borges Avatar answered May 24 '23 18:05

jonatas Borges