Flutter multiple async methods for parrallel execution
Asked Answered
M

9

61

I'm still struggeling with the async/await pattern so I'm here to ask you some precisions.

I saw this page explaining the async/await pattern pretty well. I'm posting here the example that bother me :

import 'dart:async';

Future<String> firstAsync() async {
  await Future<String>.delayed(const Duration(seconds: 2));
  return "First!";
}

Future<String> secondAsync() async {
  await Future<String>.delayed(const Duration(seconds: 2));
  return "Second!";
}

Future<String> thirdAsync() async {
  await Future<String>.delayed(const Duration(seconds: 2));
  return "Third!";
}

void main() async {
  var f = await firstAsync();
  print(f);
  var s = await secondAsync();
  print(s);
  var t = await thirdAsync();
  print(t);
  print('done');
}

In this example, each async method is called one after another, so the execution time for the main function is 6 seconds (3 x 2 seconds). However, I don't understand what's the point of asynchronous function if they are executed one after another.

Are async functions not supposed to execute in the background ? Is it not the point of multiple async functions to fastens the process with parrallel execution ?

I think I'm missing something about asynchronous functions and async/await pattern in flutter so if you could explain me that, it would be very appreciated.

Best

Macedo answered 3/4, 2019 at 19:3 Comment(1)
The keywork await "stops" the execution flow until async operation is 100% complete. If you remove that, the code will runs "non-stops".Charismatic
C
31

The example is designed to show how you can wait for a long-running process without actually blocking the thread. In practice, if you have several of those that you want to run in parallel (for example: independent network calls), you could optimize things.

Calling await stops the execution of the method until the future completes, so the call to secondAsync will not happen until firstAsync finishes, and so on. If you do this instead:

void main() async {
  var f = firstAsync();
  var s = secondAsync();
  var t = thirdAsync();
  print(await f);
  print(await s);
  print(await t);
  print('done');
}

then all three futures are started right away, and then you wait for them to finish in a specific order.

It is worth highlighting that now f, s, and t have type Future<String>. You can experiment with different durations for each future, or changing the order of the statements.

Cassaundracassava answered 7/10, 2019 at 3:1 Comment(2)
Thx for the info !Macedo
We also have FutureGroupReina
S
116

Waiting on multiple Futures to complete using Future.wait() If the order of execution of the functions is not important, you can use Future.wait().

The functions get triggered in quick succession; when all of them complete with a value, Future.wait() returns a new Future. This Future completes with a list containing the values produced by each function.

Future
    .wait([firstAsync(), secondAsync(), thirdAsyncC()])
    .then((List responses) => chooseBestResponse(responses))
    .catchError((e) => handleError(e));

or with async/await

try {
    List responses = await Future.wait([firstAsync(), secondAsync(), thirdAsyncC()]);
} catch (e) {
    handleError(e)
}

If any of the invoked functions completes with an error, the Future returned by Future.wait() also completes with an error. Use catchError() to handle the error.

Resource: https://api.flutter.dev/flutter/dart-async/Future/wait.html

Sacellum answered 22/7, 2019 at 11:28 Comment(2)
There's also FutureGroupReina
Link is not working anymore for the original answer.Salyers
C
31

The example is designed to show how you can wait for a long-running process without actually blocking the thread. In practice, if you have several of those that you want to run in parallel (for example: independent network calls), you could optimize things.

Calling await stops the execution of the method until the future completes, so the call to secondAsync will not happen until firstAsync finishes, and so on. If you do this instead:

void main() async {
  var f = firstAsync();
  var s = secondAsync();
  var t = thirdAsync();
  print(await f);
  print(await s);
  print(await t);
  print('done');
}

then all three futures are started right away, and then you wait for them to finish in a specific order.

It is worth highlighting that now f, s, and t have type Future<String>. You can experiment with different durations for each future, or changing the order of the statements.

Cassaundracassava answered 7/10, 2019 at 3:1 Comment(2)
Thx for the info !Macedo
We also have FutureGroupReina
E
19

If anyone new in this problem use the async . Dart has a function called FutureGroup. You can use it to run futures in parallel.

Sample:

final futureGroup = FutureGroup();//instantiate it

void runAllFutures() {
  /// add all the futures , this is not the best way u can create an extension method to add all at the same time
  futureGroup.add(hello());
  futureGroup.add(checkLocalAuth());
  futureGroup.add(hello1());
  futureGroup.add(hello2());
  futureGroup.add(hello3());
  
  // call the `.close` of the group to fire all the futures,
  // once u call `.close` this group cant be used again
  futureGroup.close();

  // await for future group to finish (all futures inside it to finish)
  await futureGroup.future;
}

This futureGroup has some useful methods which can help you ie. .future etc.. check the documentation to get more info.

Here's a sample usage Example One using await/async and Example Two using Future.then.

Etzel answered 3/7, 2021 at 10:4 Comment(5)
This is a good answer for an inevitable problem -- running multiple async calls without caring about their execution order but with caring that you actually await for them to finish as a group. Essentially grouping futures and waiting for their execution as a whole.Reina
What about grouping them, but then collecting their results?Firing
@MarcellodeSales u can still get all of their result by awaiting futureGroup.futuresEtzel
@MAfzal I implementation using Google's Tuple gist.github.com/marcellodesales/… ... Thank you!Firing
Great answer but would be better if mentioned that you need to include the async package to your dependencies in pub spec.yaml file like this answer.Stuffy
R
8

you can always use them in a single future

final results = await Future.wait([
  firstAsync();
  secondAsync();
  thirdAsync();
]);

results will be an array of you return type. in this case array of strings.

cheers.

Rhinelandpalatinate answered 28/1, 2021 at 7:46 Comment(0)
C
3

Try this resolve.

final List<Future<dynamic>> featureList = <Future<dynamic>>[];
for (final Partner partner in partnerList) {
  featureList.add(repository.fetchAvatar(partner.uid));
}
await Future.wait<dynamic>(featureList);
Cutaway answered 14/7, 2021 at 8:30 Comment(0)
M
1

If want parallel execution you should switch to multi thread concept called Isolates mix this with async/await concepts . You can also check this website for more

https://buildflutter.com/flutter-threading-isolates-future-async-and-await/

Mylonite answered 7/5, 2019 at 9:36 Comment(0)
C
0

With the latest versions of Dart, you can use Records to get typed results from parallel async tasks

final (f, s, t) = (firstAsync(), secondAsync(), thirdAsync()).wait;
Chibouk answered 7/5 at 12:31 Comment(0)
G
-1

Using async / await like that is useful when you need a resource before executing the next task.

In your example you don't do really useful things, but imagine you call firstAsync, that gives you a stored authorization token in your phone, then you call secondAsync giving this token get asynchronously and execute an HTTP request and then checking the result of this request.
In this case you don't block the UI thread (user can interact with your app) and other tasks (get token, HTTP request...) are done in background.

Giselegisella answered 3/4, 2019 at 19:12 Comment(0)
C
-2

i think you miss understood how flutter works first flutter is not multi threaded.....! second if it isn't multi threaded how can it executes parallel tasks, which doesnt happen....! here is some links that will help you understand more https://webdev.dartlang.org/articles/performance/event-loop https://www.dartlang.org/tutorials/language/futures

flutter doesn't put futures on another thread but what happens that they are added to a queue the links that i added are for event loop and how future works. hope you get it , feel free to ask me :)

Combo answered 3/4, 2019 at 21:27 Comment(9)
I read the doc and it's really interesting I had no idea. However, my question is what's the point of asynchronous execution ? For example, imagine I wanna fetch data from a server. I'm creating an async method with await keyword on the GET query. The async method ends and the GET query is executed when it's dequeued from the Event loop. I understand that it was done to avoid freezing the UI but if there is no parrallel execution, the GET query, even if it's executed in the future will block the UI no ?Macedo
For example, I have a CirclularProgressWheel running during the GET query, will it be freezed when the GET query is dequeud from the event loop ? If not, it means that the query is executed in the background in another thread (isolate in dart) but this is transparent for the developer ? To make a parrallel with AsyncTask in native Android, I think an ASyncTask is executed in another thread in order to avoid freezing the UI.Macedo
no it seems you didnt notice some important details and again it'snot mutli threaded however there is two queues micro tasks handles short tasks and it should finishes first before going to event queue which is where the future is executed or added.Combo
look at this image webdev.dartlang.org/articles/performance/images/both-queues.png and i will add another comment about android so that you can relate moreCombo
in android you can actually add some tasks on the main thread but still the ui doesnt freeze as it is so small tasks ,so it is the same concept some tasks wouldnt freeze the ui in flutter but when those tasks are so lengthy and would cause a freeze we use future.and how future works its like really something will happen in future even it is a timer and thus we use ".then" with future as we can order our tasks in the queue so basically saying future.then() like saying pls add this future to the queue and wait for it to happen, after that add (.then()) in the queue after itCombo
oh and i missed to say something the queues doesnt intercept what is executing in the main so normal function call would execute normally without the need to add it to the event queue .webdev.dartlang.org/articles/performance/event-loop look at question #1 for more detailsCombo
I understood that yesterday. But the thing I don't get it is what's the point of delayed heavy tasks that can freeze the UI after the main loop is done ? As it's single threaded, the heavy task will be executed after all the UI updates and so on. That's fine when the user does not interact with the UI for exampel. But what happen when a task from the event queue is processed and the user click on a button ? Is the button frozen ?Macedo
I saw this video: youtube.com/watch?v=8aGhZQkoFbQ about javascript and the event loop. Is it the same in flutter ? Like the runtime loop is single threaded but when we call Future, it's done in parrallel like the API in JS ?Macedo
yeah it is similar to that somehow , actually dart is a mix of java and javascriptCombo

© 2022 - 2024 — McMap. All rights reserved.