Flutter. Assincronia (assíncrona) <> paralelismo (isolar). De forma alguma

Introdução



Recentemente, fiquei surpreso ao descobrir que meus colegas não têm clareza completa do que é assincronia em Flutter. Por algum motivo, eles tiveram a ideia de que se a função assíncrona for escrita corretamente, ela não bloqueará a interface. Depois de ler alguns artigos, não encontrei uma explicação simples, completa e clara de toda esta cozinha (tudo está de acordo com o princípio - "escolha 2 entre 3")). Em um artigo, até li que o Dart tem uma assincronia maravilhosa, que permite adiar a execução do código até que o thread esteja mais livre (o que na minha opinião é um pouco enganador) (Nota: nos comentários nikita_dolapontou o que provavelmente significava - scheduleTask ).



Para quem o artigo



O artigo é direcionado para aqueles que estão começando a se familiarizar com o Flutter, então tentarei mostrar com um exemplo simples nesta pequena nota que assincronia é apenas a capacidade de executar código não sequencialmente. Mas, se você tiver uma função "pesada" (mesmo que seja três vezes assíncrona), ela ainda bloqueará a interface para você. Claro, em um produto real, é improvável que você encontre tais manifestações óbvias (no momento, os processadores são bastante poderosos), mas ainda vale a pena entender como isso funciona.



Vai



E então, vamos pegar um exemplo da documentação da biblioteca flutter_bloc para experimentos . Vamos modificar ligeiramente a função "_mapTimerStartedToState" da classe timer_bloc - comentar a atualização do contador para que não interfira:



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

      
      







Vamos adicionar uma nova função estática (nós a deixamos assim com antecedência - isolar funciona apenas com eles) função:



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

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

      
      







Aqui, como uma emulação de cálculos pesados, aguardamos o fim do atraso de 5 segundos.

Modificamos a função mapEventToState - adicionamos uma chamada assíncrona a _heavyComput no final:



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

. . .
  
  _heavyComput(null);
}

      
      







Para o primeiro teste, tudo está pronto - nossa tarefa é observar as ondas mágicas.

Lançamos e vemos - as ondas estão preocupadas, a interface não está bloqueada, a mensagem sobre o fim da função é exibida após 5 segundos.







Isso é assincronia maravilhosa - o pânico era falso. Hmm ... E se Future.delayed (Duration (seconds: 5)) for substituído por um 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;
}

      
      





Lançamos e pronto - “chegamos” - as ondas não preocupam mais.







Não acho que muita explicação seja necessária aqui: até mesmo uma função pesada assíncrona bloqueia tudo. Por padrão, todo o código é executado em um segmento. Só que, no primeiro caso, nenhum cálculo foi necessário, mas você apenas teve que esperar e, no segundo, os cálculos foram necessários.



Bem, e para que o artigo não se torne completamente microscópico, vamos chamar essa função usando isolar. Vamos mudar o mapEventToState:



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

      
      







Iniciamos e vemos que a interface não está bloqueada, recebemos uma mensagem sobre a conclusão da função com um atraso notável.







Isso é tudo (que trabalho assíncrono e aguardar - há muitos artigos, acho que você não deveria parar por aí).



Um exemplo pode ser baixado do link - flutter_timer_async_and_parallels



All Articles