Programmation synchrone/asynchrone

Dec 06 2022
Dans ce blog, j'essaie d'expliquer au mieux ce qu'est la programmation synchrone et asynchrone.
Si un appelant envoie un message à un destinataire et attend une réponse, peut-il faire autre chose ? Je dis un appelant/récepteur au lieu d'un serveur/client, car ces appels se produisent partout. De par sa conception, lorsque nous avons construit l'informatique pour la première fois, tout était synchrone.
Synchronisé/Asynchrone

Si un appelant envoie un message à un destinataire et attend une réponse, peut-il faire autre chose ? Je dis un appelant/récepteur au lieu d'un serveur/client, car ces appels se produisent partout. De par sa conception, lorsque nous avons construit l'informatique pour la première fois, tout était synchrone. Cela peut être vu comme une onde sinusoïdale où un appelant et un serveur sont synchronisés ou au même rythme. Asynchrone signifie qu'ils ne sont pas synchronisés.

E/S synchrone
L'appelant envoie la requête au récepteur puis la bloque. C'est alors que l'appelant est bloqué, ne fait rien, et donc une perte de temps totale. Autrefois, le processeur supprimait le processus du processeur, pensant qu'il était simplement bloqué, et ajoutait un nouveau processus qui n'est pas bloqué (commutation de contexte). Ainsi, l'appelant ne peut pas s'exécuter entre-temps. Enfin, lorsque le récepteur répond, le système d'exploitation peut renvoyer le processus au processeur. Par conséquent, l'appelant se débloque. Cela montre comment le client et le serveur sont entièrement synchronisés.

Exemple d'E/S synchrones du système d'exploitation :
1. Le programme demande au processeur de lire un fichier sur le disque.
2. Le thread principal du programme est retiré du CPU.
3. La lecture se termine et le programme recommence à s'exécuter.

// 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

Parlant spécifiquement du point de vue de NodeJs, il utilise epoll sous Linux, et dans le cas de Windows, il utilise une pile de complétion. Une autre chose que nodeJs fait est de lancer un nouveau thread qui se bloque au cas où quelque chose nécessiterait d'effectuer une opération de blocage. Par défaut, Nodejs a 4 threads de travail dans la bibliothèque libuv , qu'il utilise pour les opérations d'E/S, mais il est configurable.

Exemple d'appel asynchrone du système d'exploitation (NodeJS)
a) Le programme lance un thread secondaire
b) le thread secondaire lit à partir du disque. Évidemment, le système d'exploitation supprime du processeur actuel
c) le programme principal fonctionne et s'exécute toujours.
d) Le thread se termine et appelle le 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

Nous allons maintenant discuter des choses uniquement du point de vue d'un client et d'un serveur (backend).
Ainsi, la synchronicité peut également être connue comme une propriété client où elle peut attendre ou passer à autre chose. De nos jours, aucun client n'est synchrone et la plupart des bibliothèques sont asynchrones. La plupart du temps, le client envoie la demande, et il obtient une réponse, et certains rappels sont appelés chaque fois que la réponse est exécutée. Ainsi, dans Node.js en particulier, il existe une boucle principale de boucle d'événement qui vérifie la réponse.
Cela peut être déroutant, comme ça l'a toujours été pour moi quand quelqu'un l'expliquait avec ce bel exemple concret que synchrone, c'est comme poser une question lors d'une réunion où la réunion se poursuivra si le présentateur répond. Asynchrone, c'est comme poser une question dans un e-mail à laquelle on peut répondre chaque fois que le destinataire en a le temps.

Traitement backend asynchrone

En tant qu'ingénieur backend, il serait injuste que je ne parle pas de rendre le backend asynchrone. Dans de nombreux codes/dépôts, le client est principalement asynchrone, mais le backend le fait toujours attendre. Ainsi, lorsqu'un client demande de pousser certaines données, disons pour faire un appel à la base de données, il lui est souvent demandé d'attendre la réponse du backend, qui renvoie une réponse de statut 200 après la validation. Maintenant, si nous déplaçons l'objectif vers le backend, le frontend est asynchrone, mais le backend est toujours synchrone. Alors, comment retournons-nous une réponse immédiate ?
Une des solutions est d'utiliser cette belle structure de données, nommée file d'attente. Si un client envoie une requête, nous ne promettons pas de l'exécuter immédiatement, mais nous la jetterons dans la file d'attente. La raison en est que le backend est peut-être en train de terminer les requêtes précédentes et que le client n'est plus bloqué ; nous pouvons envoyer la réponse indiquant que nous avons mis la demande en file d'attente, et voici une promesse/ID de travail. Pour plus d'informations, vous pouvez lire sur les files d'attente de messages .
Il existe des solutions très populaires en dehors de cela, selon le cas d'utilisation.

Un exemple concret d'une charge de travail asynchrone :
a) Commits asynchrones dans Postgres ↗ .
b) E/S asynchrones sous Linux (io-uring).
c) E/S asynchrone fsync (fs-cache) : Chaque fois que nous écrivons quelque chose dans un fichier, il n'est pas écrit directement sur le disque mais dans le cache du système de fichiers. Il y a un cache dans le système d'exploitation et les écritures vont dans des pages. Et puis, le système d'exploitation vide toutes les pages en une seule fois.

Nous pouvons résumer le tout comme suit :
a) L'approche de programmation synchrone exécute les tâches de manière séquentielle. Chaque tâche est exécutée après avoir attendu la fin d'une tâche précédente.
b) Lorsqu'une tâche est exécutée dans un modèle de programmation asynchrone, on peut passer à une autre sans attendre la fin de la précédente.

Merci d'avoir lu; J'espère que cela a été utile.
En cas de doute supplémentaire, n'hésitez pas à vous connecter via LinkedIn / Instagram .