Flutter. Асинхронность (async) <> параллельность (isolate). Совсем

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Вступление


Недавно с удивлением обнаружил, что у коллег нет полной ясности, что такое асинхронность во Flutter. Почему-то у них было представление, что если асинхронная функция правильно написана, то она не блокирует интерфейс. Пролистав, пару статей не нашел простого, полного и ясного объяснения всей этой кухни (тут все по принципу — «выберите 2 из 3-х»)). В одной статье даже прочитал, что Dart обладает некоей чудесной асинхронностью, которая позволяет отложить выполнения кода, до тех пор, пока поток не будет посвободнее (что на мой взгляд вводит немного в заблуждение).

Для кого статья


Статья рассчитана на тех, кто только начинает знакомиться с Flutter, поэтому попытаюсь на простом примере в этой небольшой заметке показать, что асинхронность это всего лишь возможность выполнения кода не последовательно. Но, если у вас есть «тяжелая» функция (пусть она даже будет трижды асинхронной) она все равно заблокирует вам интерфейс. Конечно, в реальном продакте, вряд ли вы столкнетесь с такими явными проявлениями (на текущий момент процессора достаточно мощные), но понимать все-таки стоит как это работает.

Поехали


И так, возьмем для экспериментов пример из документации к библиотеке flutter_bloc. Немного модифицируем функцию "_mapTimerStartedToState" класса timer_bloc – закомментируем обновление счетчика чтобы не мешал:

Stream<TimerState> _mapTimerStartedToState(TimerStarted start) async* {
  yield TimerRunInProgress(start.duration);
  _tickerSubscription?.cancel();
  // _tickerSubscription = _ticker
  //     .tick(ticks: start.duration)
  //     .listen((duration) => add(TimerTicked(duration: duration)));
}


Добавим новую статическую (заранее делаем ее такой – isolate работает только с ними) функцию:

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(seconds: 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
Источник: https://habr.com/ru/post/541890/


Интересные статьи

Интересные статьи

Нередко при работе с Bitrix24 REST API возникает необходимость быстро получить содержимое определенных полей всех элементов какого-то списка (например, лидов). Традиционн...
И снова здравствуй. Какое-то время назад я писал о другом малоизвестном инструменте для любителей высокой производительности — System.IO.Pipelines. По своей сути, рассматриваемый Syst...
В обновлении «Сидней» Битрикс выпустил новый продукт в составе Битрикс24: магазины. Теперь в любом портале можно создать не только лендинг или многостраничный сайт, но даже интернет-магазин. С корзино...
Если честно, к Д7 у меня несколько неоднозначное отношение. В некоторых местах я попискиваю от восторга, а в некоторых хочется топать ногами и ругаться неприличными словами.
Ну ладно, не совсем. Это был маленький грязный кликбейт. Но на конференции RIPE NCC Days, прошедшей 24-25 сентября в Киеве, было анонсировано скорое окончание раздачи подсетей /22 новым LIR-ам. О...