Введение Недавно я с удивлением обнаружил, что мои коллеги не до конца понимают, что такое асинхронность во Flutter. Почему-то у них возникла мысль, что если асинхронную функцию написать правильно, то она не будет блокировать интерфейс.
Пролистав пару статей, я не смог найти простого, полного и понятного объяснения всей этой кухни (здесь все по принципу «выбирай 2 из 3»)).
В одной статье я даже прочитал, что в Dart есть какая-то замечательная асинхронность, которая позволяет отложить выполнение кода до тех пор, пока поток не освободится (что на мой взгляд немного вводит в заблуждение) (Примечание: в комментариях nikita_dol указал, что, вероятно, имелось в виду - РасписаниеЗадача ).
Для кого эта статья? Статья предназначена для тех, кто только начинает знакомиться с Flutter, поэтому в этой небольшой заметке я постараюсь на простом примере показать, что асинхронность — это всего лишь возможность выполнять код непоследовательно.
Но, если у вас «тяжелая» функция (даже если она трижды асинхронна), она все равно заблокирует ваш интерфейс.
Конечно, в реальном продукте вы вряд ли встретите столь явные проявления (процессоры на данный момент достаточно мощные), но разобраться в том, как это работает, все же стоит. Идти И так, возьмем для экспериментов пример из документации библиотеки флаттер_блок .
Немного модифицируем функцию «_mapTimerStartedToState» класса timer_bloc — закомментируем обновление счетчика, чтобы оно не мешало:
Добавим новую статическую (сделаем заранее такую — isolate работает только с ними) функцию:Stream<TimerState> _mapTimerStartedToState(TimerStarted start) async* { yield TimerRunInProgress(start.duration); _tickerSubscription?.
cancel(); // _tickerSubscription = _ticker // .
tick(ticks: start.duration) // .
listen((duration) => add(TimerTicked(duration: duration))); }
static Future<void> _heavyComput (SendPort sendPort) async {
await Future.delayed(Duration(seconds: 5));
print('=======================');
print('!!!function finished!!!');
print('=======================');
return null;
}
Здесь, в качестве эмуляции тяжелых вычислений, мы ждем окончания 5-секундной задержки.
Модифицируем функцию mapEventToState — добавим в конце асинхронный вызов _heavyComput: @override
Stream<TimerState> mapEventToState(
TimerEvent event,
) async* {
.
.
.
_heavyComput(null);
}
К первому испытанию все готово – наша задача наблюдать за волшебными волнами.
Запускаем и видим - волны волнуются, интерфейс не блокируется, через 5 секунд высвечивается сообщение об окончании функции.
Это чудесная асинхронность – паника была ложной.
Хм.
Что, если Future.delayed(Duration(секунд: 5)) заменить циклом? static Future<void> _heavyComput(SendPort sendPort) async {
int pause = 1200000000;
for (int i = 0; i < pause; i++) {}
print('=======================');
print('!!!function finished!!!');
print('=======================');
return null;
}
Запускаем и все – приехали – волны больше не волнуются.
Думаю, особых пояснений здесь не требуется: даже асинхронная тяжелая функция все блокирует. По умолчанию весь код выполняется в одном потоке.
Просто в первом случае никаких расчетов не требовалось, нужно было просто подождать, а во втором расчеты были нужны.
Ну а чтобы статья не получилась совсем микроскопической, давайте вызовем эту функцию с помощью isolate. Давайте изменим mapEventToState: @override
Stream<TimerState> mapEventToState(
TimerEvent event,
) async* {
.
.
.
var _receivePort = ReceivePort();
var _isolate = Isolate.spawn(_heavyComput, _receivePort.sendPort);
}
Запускаем его и видим, что интерфейс не заблокирован; сообщение о завершении функции получаем с заметной задержкой.
Вот и все (о том, как работают async и await — статей много, не думаю, что стоит на этом останавливаться).
Пример можно скачать по ссылке - flutter_timer_async_and_parallels Теги: #мобильная разработка #flutter #dart #async #isolat
-
Аргеландер, Фридрих Вильгельм Август
19 Oct, 24 -
Стоит Ли Amazon Instant Video Того?
19 Oct, 24 -
Почта России В Фотографиях
19 Oct, 24 -
Intel Ларраби Непрактичен
19 Oct, 24 -
Маркет Браузеров В Рунете
19 Oct, 24