Programação sincronizada/assíncrona

Dec 06 2022
Neste blog, tento explicar melhor o que é programação síncrona e assíncrona.
Se um chamador envia uma mensagem para um destinatário e está esperando por uma resposta, ele pode fazer outra coisa? Estou dizendo um chamador/receptor em vez de um servidor/cliente, pois essas chamadas acontecem em todos os lugares. Por design, quando criamos a computação pela primeira vez, tudo era síncrono.
Sincronizar/Assíncrono

Se um chamador envia uma mensagem para um destinatário e está esperando por uma resposta, ele pode fazer outra coisa? Estou dizendo um chamador/receptor em vez de um servidor/cliente, pois essas chamadas acontecem em todos os lugares. Por design, quando criamos a computação pela primeira vez, tudo era síncrono. Isso pode ser visto como uma onda senoidal em que um chamador e um servidor estão sincronizados ou no mesmo ritmo. Assíncrono significa que eles não estão sincronizados.

E/S síncrona
O chamador envia a solicitação ao receptor e a bloqueia. É quando o chamador é bloqueado, sem fazer nada e, portanto, uma perda total de tempo. Antigamente, a CPU removia o processo do processador, pensando que estava apenas bloqueado, e adicionava um novo processo que não estava bloqueado (mudança de contexto). Portanto, o chamador não pode executar enquanto isso. Finalmente, quando o receptor responde, o sistema operacional pode colocar o processo de volta no processador. Daí o chamador desbloqueia. Isso mostra como o cliente e o servidor estão totalmente sincronizados.

Exemplo de E/S síncrona do sistema operacional:
1. O programa solicita à CPU que leia um arquivo do disco.
2. O thread principal do programa é retirado da CPU.
3. A leitura é concluída e o programa inicia a execução novamente.

// A simple Js example
// Program starts
// Programs uses CPU to execute work.

SampleFunction();
// Program reads from the disk
// Program can't do anything until file loads
readfile("SyncExample.dat")

// Program resumes

Falando especificamente do ponto de NodeJs, ele usa epoll no Linux e, no caso do Windows, usa uma pilha completista. Outra coisa que o nodeJs faz é criar um novo thread que bloqueia caso algo exija uma operação de bloqueio. Por padrão, o Nodejs possui 4 threads de trabalho na biblioteca libuv , que usa para operações de E/S, mas é configurável.

Exemplo de uma chamada assíncrona do sistema operacional (NodeJS)
a) O programa ativa um thread secundário
b) o thread secundário lê do disco. Obviamente, o sistema operacional é removido do processador atual
c) o programa principal ainda é executado e executado.
d) A thread termina e chama a thread principal.

// A simple Javascript example
// Program starts
// Programs uses CPU to execute work.

SampleFunction();
// Program reads from the disk
// Program hapilly moves on to the samplefunction2
readfile("SyncExample.dat", onReadFinish(console.log))
//file is not probably read yet

SampleFunction2();
//onReadFinish function called
// executing it

Agora vamos discutir as coisas puramente do ponto de vista de um cliente e servidor (back-end).
Portanto, a sincronicidade também pode ser conhecida como uma propriedade do cliente, onde pode esperar ou seguir em frente. Atualmente, nenhum cliente é síncrono e a maioria das bibliotecas é assíncrona. Principalmente o cliente envia a solicitação e obtém uma resposta, e algum retorno de chamada é chamado sempre que a resposta é executada. Portanto, especificamente no Node.js, há um loop principal de loop de eventos que verifica a resposta.
Isso pode ser confuso, como sempre foi para mim quando alguém explicou com este belo exemplo da vida real que síncrono é como fazer uma pergunta em uma reunião em que a reunião prosseguirá se o apresentador responder. Assíncrono é como fazer uma pergunta em um e-mail que pode ser respondido sempre que o destinatário tiver tempo.

Processamento de back-end assíncrono

Sendo um engenheiro de back-end, seria injusto se eu não falasse sobre tornar o back-end assíncrono. Em muitos repositórios/códigos, o cliente é principalmente assíncrono, mas o back-end ainda o faz esperar. Portanto, quando um cliente solicita o envio de alguns dados, digamos para fazer uma chamada ao banco de dados, muitas vezes é solicitado que ele aguarde a resposta do back-end, que retorna uma resposta de status 200 após o commit. Agora, se movermos a lente para o back-end, o front-end será assíncrono, mas o back-end ainda será síncrono. Então, como retornamos uma resposta imediata?
Uma das soluções é usar essa bela estrutura de dados, chamada de fila. Se um cliente enviar uma solicitação, não prometemos executá-la imediatamente, mas a colocaremos na fila. A razão para isso é que o back-end pode estar concluindo as solicitações anteriores e o cliente não está mais bloqueado; podemos enviar a resposta de que colocamos a solicitação na fila e aqui está uma promessa/JobID. Para obter mais informações, você pode ler sobre filas de mensagens .
Existem soluções muito populares além disso, dependendo do caso de uso.

Um exemplo do mundo real de uma carga de trabalho assíncrona:
a) Confirmações assíncronas no Postgres ↗ .
b) I/O assíncrono no Linux (io-uring).
c) E/S assíncrona fsync (fs-cache): Sempre que escrevemos algo em qualquer arquivo, não é gravado diretamente no disco, mas no cache do sistema de arquivos. Há um cache no sistema operacional e as gravações vão para as páginas. E então, o sistema operacional libera todas as páginas de uma só vez.

Podemos resumir tudo da seguinte forma:
a) A abordagem de programação síncrona executa tarefas sequencialmente. Cada tarefa é executada após ter esperado a conclusão de qualquer tarefa anterior.
b) Quando uma tarefa é executada em um modelo de programação assíncrona, podemos passar para outra sem esperar que a anterior termine.

Obrigado por ler; Espero que tenha sido útil.
Em caso de dúvidas, sinta-se à vontade para se conectar no LinkedIn / Instagram .