Isolate e Event Loops


Este é o primeiro da série de artigos falando sobre Dart que, embora seja uma única thread da linguagem, oferece suporte a futures, transmissões, trabalho em segundo plano e tudo o que você precisa para escrever de maneira moderna, assíncrona e, no caso do Flutter, reativa.

.

 

Isolate

Vamos começar bem na base do que possibilita a assincronia em Dart, que é o Isolate.

Um Isolate é onde todo o código Dart é executado é como um espaço na máquina
com seu próprio pedaço de memória e uma única thread sendo executada
em um event loop.

Em muitas outras linguagens, como C++, é possível ter várias threads compartilhando a mesma memória e executando qualquer código.


O que são threads?

Thread é um pequeno programa que trabalha como um subsistema, sendo uma forma de um processo se autodividir em duas ou mais tarefas. É o termo em inglês para Linha ou Encadeamento de Execução. Essas tarefas múltiplas podem ser executadas simultaneamente para rodar mais rápido do que um programa em um único bloco ou praticamente juntas, mas que são tão rápidas que parecem estar trabalhando em conjunto ao mesmo tempo.


Mas, em Dart, cada thread fica em seu próprio Isolate, com a memória própria, e apenas processa eventos.

Falaremos disso em breve.

Muitos apps Dart executam código em um único Isolate, mas é possível ter mais de um,
se necessário.

Se você precisa executar uma computação que é tão grande que causaria perda de quadros se fosse executada em um Isolate principal, você poderia usar a função Isolate.spawn,
ou compute, no Flutter. Ambas criam um Isolate separado para processar os dados.

Isolate.spawn(
aFunctionToRun,
{'data' : ''Aqui há alguns dados'},
);

compute(
(params){
// faça alguma coisa
},
{'data': 'Aqui há alguns dados'},
)

Assim, mantém o seu principal livre para recriar e renderizar a árvore de widgets no meio-tempo.

O novo Isolate terá o próprio event loop e memória, é como o Isolate original, que, mesmo sendo o parent do novo, não tem acesso permitido.

É essa a origem do nome Isolate: os pequenos espaços são mantidos isolados uns dos outros.

Na verdade, a única forma de eles trabalharem juntos é enviando mensagens um ao outro. Um Isolate envia uma mensagem ao outro. O Isolate recebe e processa a mensagem
usando o próprio event loop.

Essa falta de memória compartilhada pode parecer restritiva, principalmente se você conhece
linguagens como Java ou C++, mas há alguns benefícios principais para programadores Dart.

Por exemplo, a alocação de memória e o garbage collection em um Isolate não precisam ser bloqueados. Há apenas uma thread.

Então, se estiver livre, a memória não sofrerá mutação. Isso funciona muito bem com apps do Flutter, que às vezes precisam criar e desfazer vários widgets rapidamente.

Essa foi uma introdução básica do Isolates.

 

Event Loop

Agora veremos o que possibilita a assincronia do código: o event loop.

Imagine a vida de um app como em uma linha do tempo, você começa aqui e termina ali,
e, no meio, há vários eventos, como um I/O do disco ou toques do usuário, todo tipo de coisas.

Seu app não consegue prever quando e em que ordem acontecem os eventos, ele precisa lidar com todos eles em uma thread única sem bloqueios.

Então, executa um event loop. É simples assim.

Ele pega o evento mais antigo da fila de eventos, processa-o, volta buscar o próximo, processa esse e assim por diante, até esvaziar a fila de eventos.

O tempo todo em que o app está rodando, você está tocando na tela, ele está baixando coisas, o temporizador apita e o event loop está dando várias voltas, processando todos os eventos um por vez.

Sempre que a ação é interrompida, a thread fica meio parada, esperando o próximo evento.

Ela pode acionar o garbage collector, buscar café, enfim.

Todas as APIs de alto nível foram usadas para programação assíncrona: futures, transmissões, assincronia e await.

Todas foram feitas sobre esse simples loop.

Por exemplo, digamos que você tenha um botão que inicie uma solicitação de rede, como este, você executa seu app, o Flutter cria o botão e o coloca na tela.

RaisedButton(
child: Text('Clique aqui'),
onPressed: () {
final myFuture = http.get('https://example.com');
myFuture.then((response){
if(response.statusCode == 200){
print('Sucesso');
}
});
},
)

Então, ele espera. O event loop fica ocioso, esperando o próximo processamento.

Outros eventos não relacionados ao botão podem surgir e acontecer enquanto o botão está lá, esperando ser clicado pelo usuário.

Até que eles o clicam, e um evento tap entra na fila. Esse evento é levado ao processamento. Flutter o analisa e o sistema de renderização diz: "Ei, essas coordenadas correspondem ao RaisedButton".

Então, o Flutter executa a função onPressed. O código inicia uma solicitação de rede que retorna o future e registra a conclusão do future usando then. É isso.

O loop concluiu o processamento do evento tap e é descartado. O onPressed era uma propriedade do RaisedButton, e estamos falando de um callback para um future.

Mas ambas essas técnicas fazem basicamente o mesmo.

São maneiras de dizer ao Flutter: "Ei, talvez você receba um tipo específico de evento mais tarde. Quando receber, execute este código".

O onPressed espera um toque e o future espera dados de rede.

Mas, da perspectiva do Dart, são apenas eventos na fila.

É assim que funciona a programação assíncrona em Dart. Futures, transmissões, assincronia e await são APIs e maneiras de você dizer ao event loop do Dart: "Execute este código mais tarde".

Se olharmos o código de exemplo, veremos exatamente como ele é dividido em blocos para eventos específicos.

Esta é a versão inicial, o evento tap e o evento response da rede.

// versão inicial
RaisedButton(
child: Text('Clique aqui'),
onPressed: () {

// evento tap
final myFuture = http.get('https://example.com');
myFuture.then((response){

// evento response
if(response.statusCode == 200){
print('Sucesso');
}
});
},
)

Quando se acostumar a trabalhar com código assíncrono, começará a reconhecer esses padrões por todos os lugares.

Entender o event loop lhe ajudará a trabalhar com APIs de níveis mais complexos.

Esse foi um panorama do Isolates, do event loop e da base do código assíncrono em Dart.

No próximo artigo, falaremos sobre Futures.

Uma API simples que você pode usar para aproveitar essas funções usando pouco código.

 


Este artigo foi feito com base na transcrição do vídeo https://www.youtube.com/watch?v=vl_AaCgudcY do canal Flutter do Youtube. Artigo transcrico com fins meramente didáticos.
86 Visualizações