Я все еще борюсь с шаблоном async/await, поэтому я здесь, чтобы попросить вас о некоторых уточнениях.
Я видел эта страница, довольно хорошо объясняющий шаблон async/await. Я публикую здесь пример, который меня беспокоит:
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');
}
В этом примере каждый метод async вызывается один за другим, поэтому время выполнения основной функции составляет 6 секунд (3 х 2 секунды). Однако я не понимаю, какой смысл в асинхронной функции, если они выполняются друг за другом.
Функции async не должны выполняться в фоновом режиме? Разве смысл нескольких async функций не ускоряет процесс с параллельным выполнением?
Я думаю, что мне чего-то не хватает в асинхронных функциях и шаблоне async/await во флаттере, поэтому, если бы вы могли объяснить мне это, я был бы очень признателен.
Лучший


Использование async / await полезно, когда вам нужен ресурс перед выполнением следующей задачи.
В вашем примере вы не делаете действительно полезных вещей, но представьте, что вы звоните firstAsync, который дает вам сохраненный токен авторизации в вашем телефоне, затем вы звоните secondAsync, передавая этот токен асинхронно и выполняя HTTP-запрос, а затем проверяя результат этого запрос.
В этом случае вы не блокируете поток пользовательского интерфейса (пользователь может взаимодействовать с вашим приложением), а другие задачи (получение токена, HTTP-запрос...) выполняются в фоновом режиме.
Я думаю, вы не поняли, как работает флаттер. Во-первых, флаттер не является многопоточным.....! во-вторых, если он не многопоточный, как он может выполнять параллельные задачи, чего не происходит ....! вот несколько ссылок, которые помогут вам понять больше https://webdev.dartlang.org/articles/performance/event-loophttps://www.dartlang.org/tutorials/language/futures
флаттер не помещает фьючерсы в другой поток, но что происходит, когда они добавляются в очередь, ссылки, которые я добавил, относятся к циклу событий и тому, как работает фьючерс. надеюсь, вы поняли, не стесняйтесь спрашивать меня :)
Я прочитал документ, и это действительно интересно, я понятия не имел. Однако мой вопрос: в чем смысл асинхронного выполнения? Например, представьте, что я хочу получить данные с сервера. Я создаю метод async с ключевым словом await в запросе GET. Метод async завершается, и запрос GET выполняется, когда он удаляется из очереди цикла событий. Я понимаю, что это было сделано, чтобы избежать зависания пользовательского интерфейса, но если нет параллельного выполнения, запрос GET, даже если он будет выполнен в будущем, заблокирует пользовательский интерфейс, нет?
Например, у меня есть CirclularProgressWheel, работающий во время запроса GET, будет ли он заморожен, когда запрос GET удаляется из цикла событий? Если нет, значит, запрос выполняется в фоновом режиме в другом потоке (изолировать в дротике), но это прозрачно для разработчика? Чтобы сделать параллель с AsyncTask в нативном Android, я думаю, что ASyncTask выполняется в другом потоке, чтобы избежать зависания пользовательского интерфейса.
нет, похоже, вы не заметили некоторых важных деталей, и снова это не многопоточное, однако есть две очереди, микрозадачи обрабатывают короткие задачи, и они должны заканчиваться первыми, прежде чем перейти в очередь событий, где будущее выполняется или добавляется.
посмотрите на это изображение webdev.dartlang.org/articles/performance/images/both-queues.png, и я добавлю еще один комментарий об Android, чтобы вы могли рассказать больше
в android вы можете добавить некоторые задачи в основной поток, но все равно пользовательский интерфейс не зависает, так как это такие маленькие задачи, поэтому это та же концепция, что некоторые задачи не заморозят пользовательский интерфейс в трепетании, но когда эти задачи настолько длинные и вызовут заморозить, мы используем future.and как future работает, как будто на самом деле что-то произойдет в будущем, даже если это таймер, и поэтому мы используем «.then» с future, поскольку мы можем упорядочивать наши задачи в очереди, поэтому в основном говорят future.then() как говоря, пожалуйста, добавьте это будущее в очередь и подождите, пока это произойдет, после этого добавьте (.then()) в очередь после него
о, и я пропустил, чтобы сказать кое-что, очереди не перехватывают то, что выполняется в основном, поэтому обычный вызов функции будет выполняться нормально без необходимости добавлять его в очередь событий. webdev.dartlang.org/articles/performance/event-loop посмотрите на вопрос № 1 для более подробной информации.
Я понял это вчера. Но я не понимаю, в чем смысл отложенных тяжелых задач, которые могут заморозить пользовательский интерфейс после завершения основного цикла? Поскольку он однопоточный, тяжелая задача будет выполняться после всех обновлений пользовательского интерфейса и так далее. Это нормально, когда пользователь, например, не взаимодействует с пользовательским интерфейсом. Но что происходит, когда задача из очереди событий обрабатывается и пользователь нажимает кнопку? Кнопка замерзла?
Я видел это видео: youtube.com/watch?v=8aGhZQkoFbQ о javascript и цикле обработки событий. В флаттере так же? Как будто цикл выполнения является однопоточным, но когда мы вызываем Future, это делается параллельно, как API в JS?
да это как-то похоже на это, на самом деле dart это смесь java и javascript
Если вам нужно параллельное выполнение, вы должны переключиться на многопоточную концепцию под названием изоляты. смешайте это с концепциями асинхронно/ожидание. Вы также можете проверить этот веб-сайт для получения дополнительной информации
https://buildflutter.com/flutter-threading-isolates-future-async-and-await/
Ожидание завершения нескольких фьючерсов с использованием Future.wait() Если порядок выполнения функций не важен, можно использовать Future.wait().
Функции запускаются в быстрой последовательности; когда все они завершаются со значением, Future.wait() возвращает новое будущее. Это Future завершается списком, содержащим значения, полученные каждой функцией.
Future
.wait([firstAsync(), secondAsync(), thirdAsyncC()])
.then((List responses) => chooseBestResponse(responses))
.catchError((e) => handleError(e));
или с асинхронным/ожиданием
try {
List responses = await Future.wait([firstAsync(), secondAsync(), thirdAsyncC()]);
} catch (e) {
handleError(e)
}
Если какая-либо из вызванных функций завершается с ошибкой, Future, возвращаемый Future.wait(), также завершается с ошибкой. Используйте catchError() для обработки ошибки.
Также есть Группа Будущего
Пример предназначен для демонстрации того, как можно дождаться долго выполняющегося процесса, фактически не блокируя поток. На практике, если у вас есть несколько из них, которые вы хотите запускать параллельно (например, независимые сетевые вызовы), вы можете оптимизировать ситуацию.
Вызов await останавливает выполнение метода до тех пор, пока не завершится будущее, поэтому вызов secondAsync не произойдет, пока не завершится firstAsync, и так далее. Если вы сделаете это вместо этого:
void main() async {
var f = firstAsync();
var s = secondAsync();
var t = thirdAsync();
print(await f);
print(await s);
print(await t);
print('done');
}
затем сразу же запускаются все три фьючерса, а затем вы ждете их завершения в определенном порядке.
Стоит подчеркнуть, что теперь f, s и t имеют тип Future<String>. Вы можете поэкспериментировать с разной продолжительностью для каждого будущего или изменить порядок утверждений.
Спасибо за информацию!
У нас также есть Группа Будущего
вы всегда можете использовать их в одном будущем
final results = await Future.wait([
firstAsync();
secondAsync();
thirdAsync();
]);
results будет массивом возвращаемого вами типа. в этом случае массив строк.
ваше здоровье.
Если кто-то новичок в этой проблеме, используйте async . В Dart есть функция под названием FutureGroup. Вы можете использовать его для параллельного запуска фьючерсов.
Образец:
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;
}
У этого futureGroup есть несколько полезных методов, которые могут вам помочь, например. .future и т. д.. проверьте документация, чтобы получить больше информации.
Вот пример использования Пример первый с использованием await/async и Пример второй с использованием Future.then.
Это хороший ответ на неизбежную проблему — запуск нескольких асинхронных вызовов, не заботясь об их порядке выполнения, но заботясь о том, чтобы вы на самом деле await чтобы они завершились как группа. По сути фьючерсы группировка и ожидание их исполнения целиком.
Как насчет того, чтобы сгруппировать их, а затем собрать их результаты?
@MarcellodeSales, вы все еще можете получить все их результаты к awaitingfutureGroup.futures
@MAfzal I реализация с использованием Google Tuple gist.github.com/marcellodesales/… ... Спасибо!
Попробуйте это решение.
final List<Future<dynamic>> featureList = <Future<dynamic>>[];
for (final Partner partner in partnerList) {
featureList.add(repository.fetchAvatar(partner.uid));
}
await Future.wait<dynamic>(featureList);
Ключевая работа
await«останавливает» поток выполнения до тех пор, пока асинхронная операция не будет завершена на 100%. Если вы удалите это, код будет работать «нон-стоп».