Quelle est la différence entre: les architectures asynchrones, non bloquantes et les bases d’événements?

  1. Quelle est la différence entre:

    • Asynchrone ,
    • Non bloquant , et
    • Architectures de base d’événement ?
  2. Quelque chose peut-il être à la fois asynchrone et non bloquant (et basé sur des événements )?

  3. Qu’est-ce qui est le plus important en programmation, d’avoir quelque chose: asynchrone, non bloquant et / ou base d’événement (ou tous les 3)?

Si vous pouviez fournir des exemples, ce serait formidable.

Cette question est posée parce que je lisais cet excellent article de StackOverflow sur un sujet similaire, mais cela ne répond pas à mes questions ci-dessus.

Asynchronous Asynchronous signifie littéralement non synchrone. Le courrier électronique est asynchrone. Vous envoyez un mail, vous ne vous attendez pas à recevoir une réponse MAINTENANT. Mais ce n’est pas non bloquant. Essentiellement, cela signifie une architecture où les “composants” envoient des messages les uns aux autres sans attendre une réponse immédiate. Les requêtes HTTP sont synchrones. Envoyer une demande et obtenir une réponse.

Non bloquant Ce terme est principalement utilisé avec IO. Cela signifie que lorsque vous effectuez un appel système, il retourne immédiatement avec le résultat obtenu sans mettre votre thread en sumil (avec une forte probabilité). Par exemple, les appels en lecture / écriture non bloquants renvoient à ce qu’ils peuvent faire et s’attendent à ce que l’appelant répète l’appel. try_lock, par exemple, est un appel non bloquant. Il ne se verrouille que si le locking peut être acquis. La sémantique habituelle pour les appels systèmes est bloquante. read attendra d’avoir des données et de mettre le thread appelant en veille.

Event-base Ce terme vient de libevent. les appels en lecture / écriture non bloquants en eux-mêmes sont inutiles car ils ne vous disent pas “quand” devez-vous les rappeler (réessayer). select / epoll / IOCompletionPort etc sont des mécanismes différents permettant de détecter le système d’exploitation “lorsque” ces appels sont censés renvoyer des données “intéressantes”. libevent et d’autres bibliothèques de ce type fournissent des wrappers sur ces fonctions de surveillance d’événements fournies par différents systèmes d’exploitation et fournissent une API cohérente avec laquelle les systèmes d’exploitation fonctionnent. IO non bloquant va de pair avec Event-base.

Je pense que ces termes se chevauchent. Par exemple, le protocole HTTP est synchrone mais l’implémentation HTTP utilisant des E / S non bloquantes peut être asynchrone. Encore une fois, un appel API non bloquant comme read / write / try_lock est synchrone (il donne immédiatement une réponse) mais la “gestion des données” est asynchrone.

Dans un matériel asynchrone, le code demande à une entité de faire quelque chose et est libre de faire d’autres choses pendant que l’action est effectuée; Une fois l’action terminée, l’entité signalera généralement le code d’une manière ou d’une autre. Une architecture non bloquante prendra note des actions spontanées susceptibles d’intéresser le code, et autorisera le code à demander quelles actions ont eu lieu, mais le code n’aura connaissance de ces actions qu’en cas d’interrogations explicites. Une architecture basée sur des événements notifiera de manière affirmative le code lorsque des événements se produisent spontanément.

Considérons un port série, à partir duquel le code voudra recevoir 1 000 octets.

Dans une architecture à lecture de blocage, le code attendra que 1000 octets soient arrivés ou qu’il décide d’abandonner.

Dans une architecture à lecture asynchrone, le code indiquera au pilote qu’il veut 1 000 octets et sera averti lorsque 1 000 octets sont arrivés.

Dans une architecture non bloquante, le code peut demander à tout moment combien d’octets sont arrivés, et peut lire une ou toutes ces données quand bon lui semble, mais le seul moyen de savoir quand toutes les données sont arrivées est de demander; Si le code veut savoir dans un quart de seconde quand le 1000e octet est arrivé, il doit vérifier à peu près toutes les quarts de seconde.

Dans une architecture basée sur des événements, le pilote du port série notifiera l’application chaque fois que des données arrivent. Le pilote ne saura pas combien d’octets l’application veut, de sorte que l’application doit être capable de gérer les notifications pour des quantités plus petites ou plus grandes que celles souhaitées par l’application.

Pour moi, le non-blocage signifie que l’exécution d’une action dans un thread ne dépend pas de l’exécution des autres threads, elle ne nécessite en particulier pas de section critique.

Asynchrone signifie que l’exécution se produit en dehors du stream de l’appelant et qu’elle est potentiellement différée. L’exécution se produit généralement dans un autre thread.

La lecture de données simultanées est non bloquante (pas besoin de verrouiller), mais synchrone. Inversement, l’écriture simultanée de données de manière synchrone bloque (nécessite un verrou exclusif). Un moyen de le rendre non bloquant du sharepoint vue du stream principal consiste à rendre les écritures asynchrones et à différer leur exécution.

Le concept d’événement est autre chose, ce qui signifie en gros que vous êtes informé quand quelque chose se produit. Si des écritures ont été exécutées de manière asynchrone, un événement peut être déclenché pour informer les autres parties du système une fois que l’écriture a été exécutée. Les autres parties répondront à l’événement. Le système peut être construit uniquement sur des événements comme seul moyen de communiquer entre les composants (pensez au modèle de l’acteur), mais cela ne doit pas nécessairement être le cas.

Les trois termes sont liés, mais ce sont des concepts différents pour moi. Il se peut cependant que les gens les utilisent de manière interchangeable.

Généralement, une architecture non bloquante est basée sur des appels de méthode qui, bien qu’ils puissent s’exécuter longtemps sur le thread de travail , ne bloquent pas le thread appelant . Si le thread appelant doit acquérir des informations sur ou à partir de la tâche que le thread de travail exécute, c’est au thread appelant de le faire.

Une architecture basée sur des événements repose sur le concept de code exécuté en réponse à des événements déclenchés. La synchronisation de l’exécution du code n’est généralement pas déterministe, mais les événements peuvent invoquer des méthodes de blocage; le fait qu’un système soit basé sur des événements ne signifie pas que tout ce qu’il fait ne bloque pas.

En général, une architecture asynchrone est une architecture non bloquante basée sur les événements.

Lorsqu’un appel asynchrone est effectué, les gestionnaires d’événements sont enregistrés auprès de l’API fournissant des services de synchronisation, afin d’informer l’appelant que quelque chose d’intéressé est arrivé. L’appel retourne alors immédiatement (comportement non bloquant) et l’appelant est libre de continuer l’exécution. Lorsque des événements sont renvoyés au processus appelant, ils seront traités sur un thread dans ce processus.

Il est important de comprendre si les événements seront traités ou non sur le même thread, car cela affectera la nature non bloquante de l’exécution, mais je ne connais pas de bibliothèques effectuant une gestion d’exécution asynchrone sur un seul thread.

J’ai supprimé le paragraphe ci-dessus parce que ce n’est pas ssortingctement correct comme indiqué. Mon intention était de dire que même si les opérations dans le système ne bloquent pas, comme émettre des appels vers un système d’exploitation et poursuivre l’exécution, la nature de l’exécution mono-thread signifie que lorsque des événements sont déclenchés, ils seront en concurrence avec autres tâches de traitement pour le temps de calcul sur le thread.

Donc, pour répondre à votre première et deuxième question:

Le fait de ne pas bloquer est en fait le même que le mode asynchrone: vous effectuez l’appel et vous obtiendrez un résultat plus tard, mais pendant que cela se produit, vous pouvez faire autre chose. Le blocage est le contraire. Vous attendez que l’appel revienne avant de continuer votre voyage.

Maintenant, le code Async / Non-blocking est absolument fantastique, et ça l’est. Mais j’ai des mots d’avertissement. Les fonctions asynchrones / non bloquantes sont excellentes lorsque vous travaillez dans des environnements restreints, par exemple sur un téléphone portable … considérez le nombre limité de CPU / mémoire. C’est aussi bon pour le développement frontal, où votre code doit réagir à un widget d’interface utilisateur d’une manière ou d’une autre.

L’async est fondamental pour la façon dont tous les systèmes d’exploitation doivent fonctionner: ils vous confient la merde en arrière-plan et rehaussent votre code quand ils ont fait ce que vous aviez demandé. fonctionnent soit par une exception, soit par une sorte d’object retour code / erreur.

Au moment où votre code demande quelque chose qui prendra du temps pour répondre, votre système d’exploitation sait qu’il peut être occupé à faire d’autres choses. Votre code – un processus, un thread ou équivalent, des blocs. Votre code ne tient absolument pas compte de ce qui se passe dans le système d’exploitation pendant l’attente de la connexion réseau, ou pendant l’attente de cette réponse à partir d’une requête HTTP, ou pendant l’attente de la lecture / écriture d’un fichier, et bientôt. Votre code pourrait “simplement” attendre un clic de souris. Pendant ce temps, votre système d’exploitation gérait, planifiait et réagissait de façon transparente aux «événements», des éléments recherchés par le système d’exploitation, tels que la gestion de la mémoire, les E / S (clavier, souris, disque, Internet). autres tâches, reprise après échec, etc.

Les systèmes d’exploitation sont rigides. Ils sont vraiment bons pour cacher toutes les choses compliquées asynchrones / non bloquantes de votre part, le programmeur. Et c’est comme ça que la plupart des programmeurs sont arrivés là où nous sums aujourd’hui avec les logiciels. Maintenant, nous atteignons les limites du processeur, les gens disent que les choses peuvent être faites en parallèle pour améliorer les performances. Cela signifie qu’Async / non-blocage semble être une chose très favorable à faire, et oui, si votre logiciel l’exige, je peux être d’accord.

Si vous écrivez un serveur Web principal, procédez avec précaution. Rappelez-vous que vous pouvez mettre à l’échelle horizontalement pour beaucoup moins cher. Netflix / Amazon / Google / Facebook sont des exceptions évidentes à cette règle, simplement parce que cela leur coûte moins cher d’utiliser moins de matériel.

Je vais vous dire pourquoi le code asynchrone / non bloquant est un cauchemar avec les systèmes back-end ….

1) Cela devient un déni de service sur la productivité … vous devez penser BEAUCOUP plus, et vous faites beaucoup d’erreurs en cours de route.

2) Les traces de stack dans le code réactif deviennent indéchiffrables – il est difficile de savoir ce qu’on appelle quoi, quand, pourquoi et comment. Bonne chance avec le débogage.

3) Vous devez réfléchir davantage à la manière dont les choses échouent, en particulier lorsque beaucoup de choses reviennent dans l’ordre dans lequel vous les avez envoyées. Dans l’ancien monde, vous avez fait une chose à la fois.

4) Il est plus difficile de tester.

5) C’est plus difficile à maintenir.

6) C’est douloureux. La programmation devrait être une joie et un plaisir. Seuls les masochistes aiment la douleur. Les personnes qui écrivent des frameworks concurrents / réactifs sont des sadiques.

Et oui, j’ai écrit sync et async. Je préfère le synchrone car 99,99 des applications dorsales peuvent se débrouiller avec ce paradigme. Les applications frontales ont besoin de code réactif, sans aucun doute, et cela a toujours été le cas.

  1. Oui, le code peut être asynchrone, non bloquant ET basé sur des événements.

  2. La chose la plus importante en programmation est de vous assurer que votre code fonctionne et répond dans un délai acceptable. Respectez ce principe clé et vous ne pouvez pas vous tromper.