Flutter. Asynchrony (async) <> parallelism (isolate). At all

Introduction



Recently, I was surprised to find that my colleagues do not have complete clarity of what asynchrony is in Flutter. For some reason, they had the idea that if an asynchronous function is written correctly, then it does not block the interface. Having scrolled through a couple of articles, I did not find a simple, complete and clear explanation of this whole kitchen (everything is according to the principle - "choose 2 out of 3")). In one article I even read that Dart has some wonderful asynchrony, which allows you to postpone code execution until the thread is freer (which, in my opinion, is a little misleading) (Note: in the comments nikita_dolpointed out what probably meant - scheduleTask ).



For whom the article



The article is intended for those who are just starting to get acquainted with Flutter, so I will try to show with a simple example in this small note that asynchrony is just the ability to execute code not sequentially. But, if you have a "heavy" function (even if it is three times asynchronous) it will still block the interface for you. Of course, in a real product, you are unlikely to encounter such obvious manifestations (at the moment, the processors are quite powerful), but it's still worth understanding how it works.



Go



And so, let's take an example from the documentation for the flutter_bloc library for experiments . Let's slightly modify the "_mapTimerStartedToState" function of the timer_bloc class - comment out the counter update so that it doesn't interfere:



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

      
      







Let's add a new static function (we make it like this in advance - isolate works only with them) function:



static Future<void> _heavyComput (SendPort sendPort) async {
  await Future.delayed(Duration(seconds: 5));

  print('=======================');
  print('!!!function finished!!!');
  print('=======================');
  return null;
}

      
      







Here, as an emulation of heavy calculations, we are waiting for the end of the delay of 5 seconds.

We modify the mapEventToState function - add an asynchronous call to _heavyComput at the end:



@override
Stream<TimerState> mapEventToState(
  TimerEvent event,
) async* {

. . .
  
  _heavyComput(null);
}

      
      







For the first test, everything is ready - our task is to observe the magic waves.

We launch and see - the waves are worried, the interface is not blocked, a message about the end of the function is displayed after 5 seconds.







This is wonderful asynchrony - the panic was false. Hmm ... What if Future.delayed (Duration (seconds: 5)) is replaced with a loop?



static Future<void> _heavyComput(SendPort sendPort) async {
  int pause = 1200000000;
  for (int i = 0; i < pause; i++) {}
  print('=======================');
  print('!!!function finished!!!');
  print('=======================');
  return null;
}

      
      





We launch it and that's it - โ€œarrivedโ€ - the waves no longer worry.







I don't think much explanation is needed here: even an asynchronous heavy function blocks everything. By default, all code is executed in one thread. It's just that in the first case, no calculations were required, but you just had to wait, and in the second, calculations were needed.



Well, and so that the article does not turn out to be completely microscopic, let's call this function using isolate. Let's change the mapEventToState:



@override
Stream<TimerState> mapEventToState(
  TimerEvent event,
) async* {
. . .
  var _receivePort = ReceivePort();
  var _isolate = Isolate.spawn(_heavyComput, _receivePort.sendPort);
}

      
      







We start it and see that the interface is not blocked, we receive a message about the completion of the function with a noticeable delay.







That's all (how async and await work - there are many articles, I think you shouldn't stop there).



An example can be downloaded from the link - flutter_timer_async_and_parallels



All Articles