Executando processos paralelos com Flutter/DART
Tags: isolates, thread, dart, isolate
Published: 2024-04-26 14:18:42

### Executando processos paralelos com Flutter/DART

O Flutter que conhecemos tem uma execução num único thread e essa thread é executada em único, o que chamamos, de isolate.

Essa isolate, conhecida como main isolate, e as vezes necessitamos executar processos que podem gerar concorrência então a main isolate faz toda a gerência de seu event loop para que possamos executar códigos de forma assíncrona.

Então quer dizer que se eu tiver uma tarefa que executa muito tempo basta colocar no event loop que não terei problema? errado! há casos que temos tarefas muito pesados que causara gargalo em meu event loop (que também contém instruções de renderização) e irá causar travamentos (janks) na tela.

![](https://cdn-images-1.medium.com/max/800/1*k6NZW_99xedjfLY7RqOHww.png)

![](https://cdn-images-1.medium.com/max/800/1*rdWmLPYm2mtzjuhyUPlAiw.gif)

No exemplo acima temos uma animação que roda constantemente, mas perceba-se que quando executamos uma função, no caso o cálculo de Fibonacci, que é um cálculo custoso.

{% gist https://gist.github.com/toshiossada/44214a9b2ce2c826d3fd57986df5f381 file=fibanacci.dart %}

Nesse caso a solução seria fazer um processamento paralelo ao main isolate criando um novo isolate (já que Future, event loops, etc NÃO É processamento paralelo).

Mas o que são isolates?

O dart utiliza isolates que executam suas instruções de forma sequencial e em uma região da memória dedicada a ela. Cada isolate tem sua memória dedicada e seu próprio event loop que são isolados para esse propósito. diferente das threads esses isolates não podem acessar os dados um dos outros diretamente. Toda comunicação deve ser feita através de mensagens.

Afim de prever alguns erros comuns na utilização de threads como: mutabilidade de dados, os clássicos problemas de bloqueios, _dead-locks,_ etc. que são bastante comuns em programação paralela.

![](https://cdn-images-1.medium.com/max/800/1*sQ1ZweJd7jSyM9ySvH-Egw.gif)

Para trabalharmos para criar isolates existem basicamente duas formas, a primeira forma mais simples é utilizando o método **compute().**

O método **compute()** recebe 2 parâmetros, o primeiro é um método(**NOTE QUE ESSE MÉTODO NECESSITA SER STATIC**) que será executado dentro da isolate que será criado e o outro é o parâmetro que irá passar da main isolate para a nova isolate.

![](https://cdn-images-1.medium.com/max/800/1*MelqvpAwqKbC5x4foLrAeA.png)

Ao final da execução da isolate ela irá retornar um valor para a mais isolate, não há necessidade de preocupar com o fechamento da isolate e não há comunicação por mensagens entre a isolate criada e a main isolate.

A segunda forma mais completa é utilizando o **Isolate.spawn()**, este também possui dois parâmetros igualmente o **compute()**.

![](https://cdn-images-1.medium.com/max/800/1*CwtQniM95s_xYw786Lzf6g.png)

Nesse caso criamos um Objeto chamado **Message** que iremos utilizar como parâmetro do método a ser executado dentro da isolate, criamos o **ReceiverPort** que é uma abstração que implementa uma stream através dele conseguimos passar o **sendPort** para a nova **isolate**. Através deles conseguimos fazer a comunicação entre as duas isolates, onde as mensagens enviadas pelo **sendPort** são capturadas no **ReceivePort** e como trata de uma **Stream**, podemos escutar essas mensagens.

{% gist https://gist.github.com/toshiossada/0539eadb4af1524bf32a15d831d531af file=spawn.dart %}


O método **Isolate.exit()** faz a transferência de dados para o **Isolate** receptor, que nesse exemplo seria o main.

Algumas vantagens na utilização de isolates são:

> A possibilidade de execução de operações computacionais custosas de forma performática;
> Possibilita a experiencia fluida de animações.

Então agora vou utilizar isolates a rodo em meu projeto? Não, nem tudo são flores, então existem desvantagens de utilizar isolates, como:

> Complexidade de código;
> É um processo extremamente custoso ao dispositivo, principalmente em questão de memória.

Então nosso exemplo do Fibonacci ficaria da seguinte forma.

{% gist https://gist.github.com/toshiossada/1656d4c1ba7be1782a19adcfe1ec7128 file=calc.dart %}

Note que não há mais problemas de janks na execução do calculo.

![](https://cdn-images-1.medium.com/max/800/1*i3EbD2c8V_FE1VnxSE-Stw.gif)

Agora imagine o caso em que eu preciso que você tem um aplicativo aplicando todos os bons conceitos do SOLID e utiliza um package de **service locator** para resolver as dependências de sua classe?

{% gist https://gist.github.com/toshiossada/6db7a2a1999e2a5cb4d27942bc5d2908 file=home_controller.dart %}

Você recebe a **usecase** por construtor da **controller.**

![](https://cdn-images-1.medium.com/max/800/1*Zz21yJ7OFxYiRAGMN3cAyw.png)

E tenta executar o caso de uso dentro da isolate.

![](https://cdn-images-1.medium.com/max/800/1*y-LZd2y_Y5RJbBIC6Z_YsQ.png)

Isso não será possível simplesmente pelo fato de que a inicialização dos **Binds** (no caso do Modular) terem sido feito na memória da main isolate e como não há compartilhamento de memoria entre os isolates. Uma solução é fazer a inicialização dos **Binds** novamente do package que escolheu para **service locator**.

No caso do Flutter Modular podemos criar um modulo isolado contendo todas as instancias de classe que iremos utilizar dentro do isolate.

![](https://cdn-images-1.medium.com/max/800/1*cdGy6hsGEPYBo8-lhlBQ0Q.png)

{% gist https://gist.github.com/toshiossada/0f0d807da4ac5dc738c950cc90998252 file=register_isolate_module.dart %}

e através do **Modular.init()** podemos inicializar dentro da isolate o modulo novo.

{% gist https://gist.github.com/toshiossada/eb7c29d292510bfbfa4ce55341bbdb3c file=home_controller.dart %}

![](https://cdn-images-1.medium.com/max/800/1*MKfaTGYJpxA6xzbmV47cJQ.png)

Dessa forma conseguimos recuperar as instancias através do **Modular.get().**

Legal né? Muito simples fazer programaçao paralela no Dart, tem um exemplo muito legal no meu github, entre lá confira e dar estrelinha no repositório.

https://github.com/toshiossada/hive_example

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/obcg0d2y00yddve9quky.png)


Entre em nosso discord para interagir com a comunidade: https://discord.com/invite/flutterbrasil
https://linktr.ee/flutterbrasil