top of page

Simplificando a Programação Assíncrona

O que é programação assíncrona?


Uma abordagem que permite que um programa execute várias tarefas de forma concorrente e não bloqueante, ao em vez de executá-las sequencialmente.


Diferença de paralelo e concorrência


Concorrência se refere à ideia de que várias tarefas estão sendo gerenciadas ao mesmo tempo, mas não necessariamente executando ao mesmo tempo. Em um ambiente de programação concorrente, o sistema operacional ou o ambiente de execução podem alternar entre as tarefas de maneira rápida e frequente, dando a ilusão de que várias tarefas estão acontecendo simultaneamente, mesmo que uma tarefa não esteja realmente terminando antes que outra comece.

Paralelismo se refere à execução real e simultânea de tarefas em processadores diferentes. Isso ocorre quando um programa é executado em um sistema com múltiplos núcleos de CPU, permitindo que tarefas diferentes sejam realmente executadas ao mesmo tempo. O paralelismo é mais eficaz quando há tarefas independentes que podem ser executadas em núcleos separados.


Exemplo: Um estudante universitário tem várias disciplinas para estudar durante o semestre, cada disciplina seria uma tarefa a ser realizada




pessoa estudando

Concorrência: gerenciar várias tarefas de maneira intercalada, alternando entre elas ao longo do tempo, ou seja, dedicar um pouco de tempo para estudar cada disciplina em diferentes momentos do dia, ou seja, alternando entre as disciplinas, exemplo: a cada 120 minutos de estudo, ele estuda 30 minutos de álgebra, 30 minutos de química, 30 minutos de física e 30 minutos de cálculo.




cabeça quebra-cabeça

Paralelismo: executar várias tarefas simultaneamente, ou seja, você precisaria dividir seu cérebro em 4 grupos, e cada grupo seria responsável por estudar cada uma dessas matérias ao mesmo tempo.



Um exemplo mais plausível para uma tarefa que ocorre de maneira paralela seria o processo de uma banda em tocar uma música.


 

Quando utilizar programação assíncrona?

Quando você está lidando com operações que envolvem entrada/saída, como carregamento de dados de um servidor, leitura/gravação de arquivos, acesso a bancos de dados, a programação assíncrona é essencial. Pois assim, o aplicativo continuará responsivo, mesmo aguardando o resultado dessas operações.


Quando não utilizar programação assíncrona?


Para tarefas simples e rápidas que podem ser concluídas instantaneamente, a introdução de programação assíncrona pode adicionar complexidade desnecessária ao código.


Como funciona?


As tarefas são iniciadas em segundo plano, permitindo que o programa continue a funcionar sem esperar que a tarefa seja concluída. Quando a tarefa assíncrona é finalizada, ela pode notificar o programa principal e fornecer os resultados ou continuar executando código para lidar com esses resultados.



 

Problemas comuns


Callback hell (aninhamento de callbacks)

Trata-se de uma situação em que há um aninhamento excessivo de funções de retorno de chamada.

Imagine que você está seguindo uma receita de bolo que envolve várias etapas, e cada etapa requer um certo tempo de espera. Você está cozinhando o bolo com um amigo por diversão. Cada etapa do processo é assíncrona porque envolve esperar o bolo assar, o glacê endurecer etc. Você quer que a experiência seja colaborativa e, portanto, decide dividir as tarefas entre você e seu amigo.

No entanto, as coisas podem ficar complicadas se vocês dois não coordenarem bem as etapas e as esperas. Por exemplo:

  • Você prepara a massa do bolo e a coloca no forno para assar.

  • Enquanto espera, você pede ao seu amigo para preparar o glacê.

  • Seu amigo começa a fazer o glacê, mas percebe que precisa de ovos. Ele pede para você pegar ovos na geladeira.

  • Você sai para pegar os ovos, enquanto seu amigo aguarda.

  • Quando você volta com os ovos, o bolo já assou, e você o tira do forno.

  • Agora você precisa esperar o bolo esfriar antes de aplicar o glacê.

  • Enquanto espera, seu amigo termina de preparar o glacê.

  • Ele está pronto, mas você ainda precisa finalizar a aplicação do glacê.

  • Nesse cenário, vocês estão tentando coordenar etapas assíncronas e espera entre vocês dois, mas as coisas ficam confusas rapidamente. Um está esperando pelo outro, e as etapas não estão alinhadas de maneira eficiente.

cozinheira com bolo

Race Conditions (corrida de dados)


Trata-se de uma situação em que duas ou mais ações concorrentes competem para acessar ou modificar um recurso compartilhado, como uma variável ou um arquivo, e o resultado final depende de qual ação é executada primeiro. Isso pode levar a resultados inesperados ou erros no comportamento do programa.

Vamos imaginar que você e um amigo estão tentando pegar o último pedaço de pizza em uma caixa. Ambos estão com muita fome e correm para pegar o pedaço. No entanto, não há regra clara sobre quem tem prioridade. Se vocês dois pegarem o pedaço de pizza ao mesmo tempo, pode acontecer o seguinte:

  • Você e seu amigo estendem a mão para pegar o pedaço de pizza simultaneamente.

  • Ambos percebem que o pedaço de pizza está sendo agarrado por outra pessoa.

  • Vocês dois soltam o pedaço de pizza rapidamente.

  • O pedaço de pizza cai no chão com o recheio para baixo, e com isso não pode mais ser comido.

  • Neste exemplo, a "race condition" ocorre porque vocês dois estão competindo pelo mesmo recurso (o pedaço de pizza), e o resultado é incerto. O resultado final depende de quem chega primeiro e de como eles reagem quando percebem a competição.


pedaço de pizza

Deadlocks


Um "deadlock" ocorre quando dois ou mais processos ou threads ficam bloqueados, incapazes de continuar suas operações porque cada um está esperando que o outro libere um recurso necessário.

Imagine que você está em um estacionamento e avista uma vaga a sua frente, entretanto um carro vindo no sentido oposto decidiu fazer a manobra para estacionar junto com você, como vocês dois tentaram estacionar ao mesmo tempo, um bloqueou o outro, ou seja, nenhum, nem outro conseguem estacionar na vaga.



vaga de estacionamento


Código difícil de ler e manter


Trechos de código que envolvem muitas operações assíncronas aninhadas, callbacks ou promessas encadeadas. Esse tipo de código pode se tornar complexo, confuso e difícil de entender, o que torna a manutenção e o diagnóstico de erros mais complicados.


pessao lendo com dúvidas

 

Técnicas existentes no swift


GCD (Grand Central Dispatch):


Funcionamento: O GCD é uma tecnologia da Apple para a execução concorrente de tarefas em dispositivos com iOS e macOS. Ele gerencia a criação, o escalonamento e a sincronização de threads automaticamente.


Vantagens:

  • Abstrai a complexidade da gerência manual de threads.

  • Oferece um conjunto de filas para agendar e executar tarefas de forma eficiente.

  • Pode aproveitar automaticamente múltiplos núcleos de CPU.

Desvantagens:

  • Pode ser complexo de entender e depurar quando usado de maneira inadequada.

  • A concorrência pode levar a problemas de sincronização e condições de corrida se não for tratada corretamente.

Para saber mais:


Operações:


Funcionamento: As Operation e OperationQueue são classes do iOS/macOS que encapsulam unidades de trabalho. Elas oferecem uma abstração de nível superior para tarefas assíncronas e sincronização.


Vantagens:

  • Permitem encadear tarefas e definir dependências entre elas.

  • Facilitam o cancelamento e pausa de operações.

Desvantagens:

  • Podem ser mais verbosas do que GCD para tarefas simples.

  • Ainda requer atenção ao gerenciamento de threads e sincronização.

Para saber mais:


Promises:


Funcionamento: Promises são um padrão de programação assíncrona que permite trabalhar com resultados futuros de operações. Elas ajudam a melhorar a legibilidade do código que envolve várias etapas assíncronas.


Vantagens:

  • Torna o código mais legível e evita o "callback hell".

  • Facilita a gestão de fluxo assíncrono.

Desvantagens:

  • Não faz parte da API padrão da Apple e exige a adoção de bibliotecas de terceiros.

  • Pode ter curva de aprendizado para quem não está familiarizado com o conceito.

Para saber mais:


async/await:


Funcionamento: Introduzido no Swift, o async/await é uma construção que permite escrever código assíncrono de forma síncrona. O código assíncrono é marcado com a palavra-chave async, e as funções await esperam a conclusão de operações assíncronas.


Vantagens:

  • Torna o código assíncrono muito mais similar à programação síncrona.

  • Evita a necessidade de callbacks ou promessas.

Desvantagens:

  • Disponível apenas a partir do Swift 5.5 e em versões mais recentes.

  • Pode não ser adequado para todos os cenários assíncronos.

Para saber mais:


95 visualizações0 comentário

Posts recentes

Ver tudo

Comentários


bottom of page