web-dev-qa-db-fra.com

asynchrone vs non bloquant

Quelle est la différence entre les appels asynchrones et non bloquants? Aussi entre le blocage et les appels synchrones (avec des exemples s'il vous plaît)?

344
user331561

Dans de nombreuses circonstances, ce sont des noms différents pour la même chose, mais dans certains contextes, ils sont très différents. Donc ça dépend. La terminologie n'est pas appliquée de manière totalement cohérente dans l'ensemble du secteur des logiciels.

Par exemple, dans l'API sockets classique, une socket non bloquante est simplement renvoyée immédiatement avec un message d'erreur spécial "bloquerait", alors qu'une socket bloquante aurait bloqué. Vous devez utiliser une fonction distincte telle que select ou poll pour savoir quand est le bon moment pour réessayer.

Toutefois, les sockets asynchrones (pris en charge par les sockets Windows) ou le modèle asynchrone IO utilisé dans .NET sont plus pratiques. Vous appelez une méthode pour démarrer une opération et le framework vous rappelle quand c'est fait. Même ici, il existe des différences fondamentales. Les sockets Win32 asynchrones "rassemblent" leurs résultats dans un thread d'interface graphique spécifique en transmettant des messages Window, alors que IO asynchrone .NET est à thread libre (vous ne savez pas sur quel thread votre callback sera appelé).

Donc, ils ne signifient pas toujours la même chose. Pour distiller l'exemple de socket, nous pourrions dire:

  • Blocage et synchrone signifient la même chose: vous appelez l'API, il raccroche le fil jusqu'à ce qu'il ait une sorte de réponse et vous le retourne.
  • Non bloquant signifie que si une réponse ne peut pas être renvoyée rapidement, l'API renvoie immédiatement avec une erreur et ne fait rien d'autre. Il doit donc exister un moyen connexe de demander si l'API est prête à être appelée (autrement dit, pour simuler une attente de manière efficace, afin d'éviter une interrogation manuelle dans une boucle serrée).
  • Asynchrone signifie que l'API retourne toujours immédiatement après avoir lancé un effort "d'arrière-plan" pour répondre à votre demande. Il doit donc exister un moyen connexe pour obtenir le résultat.
280
Daniel Earwicker
  • Asynchrone se réfère à quelque chose de fait en parallèle, est un autre thread.
  • non bloquant fait souvent référence à interrogation, c’est-à-dire vérifier si la condition donnée est maintenue (la socket est lisible, le périphérique contient plus de données, etc.)
43
Nikolai Fetissov

synchrone/asynchrone est de décrire la relation entre deux modules.
blocage/non blocage consiste à décrire la situation d’un module.

Un exemple:
Module X: "I".
Module Y: "librairie".
X demande à Y: avez-vous un livre intitulé "c ++ primer"?

1) blocage: avant que Y ne réponde à X, X attend toujours la réponse. Maintenant X (un module) bloque. X et Y sont deux threads ou deux processus ou un thread ou un processus? Nous ne savons pas.

2) non bloquant: avant que Y ne réponde à X, X s'en va et fait autre chose. X peut revenir toutes les deux minutes pour vérifier si Y a terminé son travail? Ou X ne reviendra pas avant que Y l'appelle? Nous ne savons pas. Nous savons seulement que X peut faire d'autres choses avant que Y termine son travail. Ici, X (un module) est non bloquant. X et Y sont deux threads ou deux processus ou un processus? Nous ne savons pas. MAIS nous sommes sûrs que X et Y ne pourraient pas être un seul fil.

3) synchrone: avant que Y ne réponde à X, X attend toujours la réponse. Cela signifie que X ne peut pas continuer jusqu'à ce que Y termine son travail. Maintenant, on dit: X et Y (deux modules) sont synchrones. X et Y sont deux threads ou deux processus ou un thread ou un processus? Nous ne savons pas.

4) asynchrone: avant que Y ne réponde à X, X en sort et X peut effectuer d'autres tâches. X ne reviendra pas avant que Y l'appelle. On dit maintenant: X et Y (deux modules) sont asynchrones. X et Y sont deux threads ou deux processus ou un processus? Nous ne savons pas. MAIS nous sommes sûrs que X et Y ne pourraient pas être un seul fil.


S'il vous plaît prêter attention aux deux phrases en gras ci-dessus. Pourquoi la phrase en gras du 2) contient-elle deux cas alors que la phrase en gras du 4) ne contient qu'un seul cas? C'est une clé de la différence entre non-bloquant et asynchrone.

Voici un exemple typique de non-blocage et synchrone:

// thread X
while (true)
{
    msg = recv(Y, NON_BLOCKING_FLAG);
    if (msg is not empty)
    {
        break;
    }
    sleep(2000); // 2 sec
}

// thread Y
// prepare the book for X
send(X, book);

Vous pouvez voir que cette conception est non bloquante (vous pouvez dire que la plupart du temps, cette boucle est absurde, mais aux yeux de la CPU, X est en cours d'exécution, ce qui signifie que X n'est pas bloquant), alors que X et Y sont synchrones, car X peut Continuez à faire autre chose (X ne peut pas sortir de la boucle) jusqu'à ce qu'il obtienne le livre de Y.
Normalement, bloquer X est bien meilleur parce que le non-blocage dépense beaucoup de ressources pour une boucle stupide. Mais cet exemple est utile pour vous aider à comprendre le fait: non-blocage ne signifie pas asynchrone.

Les quatre mots nous confondent facilement. Ce que nous devrions nous rappeler, c’est que ces quatre mots servent à la conception de l’architecture. Apprendre à concevoir une bonne architecture est le seul moyen de les distinguer.

Par exemple, nous pouvons concevoir un tel type d'architecture:

// Module X = Module X1 + Module X2
// Module X1
while (true)
{
    msg = recv(many_other_modules, NON_BLOCKING_FLAG);
    if (msg is not null)
    {
        if (msg == "done")
        {
            break;
        }
        // create a thread to process msg
    }
    sleep(2000); // 2 sec
}
// Module X2
broadcast("I got the book from Y");


// Module Y
// prepare the book for X
send(X, book);

Dans l'exemple ici, nous pouvons dire que

  • X1 est non bloquant
  • X1 et X2 sont synchrones
  • X et Y sont asynchrones

Si vous avez besoin, vous pouvez également décrire les threads créés dans X1 avec les quatre mots.

Les choses les plus importantes sont: quand utilisons-nous synchrone au lieu d’asynchrone? Quand utilise-t-on le blocage au lieu du non-blocage?

Pourquoi Nginx ne bloque-t-il pas? Pourquoi Apache est-il bloquant?

Pour faire un bon choix, vous devez analyser votre besoin et tester les performances de différentes architectures. Une telle architecture ne convient pas à divers besoins.

41
Yves

En plaçant cette question dans le contexte de NIO et NIO.2 dans Java 7, async _ (IO] _ est une étape plus avancée que le non-blocage. Avec Java NIO appels non bloquants, vous définissez tous les canaux (SocketChannel, ServerSocketChannel, FileChannel, etc.) comme tels en appelant AbstractSelectableChannel.configureBlocking(false). Après le retour de ces IO, vous devrez probablement contrôler les vérifications, par exemple si et quand lire/écrire à nouveau, etc.
Par exemple,

while (!isDataEnough()) {
    socketchannel.read(inputBuffer);
    // do something else and then read again
}

Avec l’API asynchrone dans Java 7, ces contrôles peuvent être configurés de différentes manières. L'une des deux méthodes consiste à utiliser CompletionHandler. Notez que les deux appels read ne sont pas bloquants.

asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */, 
    new CompletionHandler<Integer, Object>() {
        public void completed(Integer result, Object attachment) {...}  
        public void failed(Throwable e, Object attachment) {...}
    }
}
15
Anthony

Comme vous pouvez probablement le voir sur la multitude de réponses différentes (et souvent mutuellement exclusives), cela dépend de qui vous demandez. Dans certaines arènes, les termes sont synonymes. Ou ils pourraient chacun se référer à deux concepts similaires:

  • L’une des interprétations est que l’appel fera quelque chose à l’arrière-plan essentiellement sans surveillance afin de permettre au programme de ne pas être retardé par un long processus qu’il n’a pas besoin de contrôler. La lecture de l’audio peut être un exemple: un programme peut appeler une fonction pour lire (par exemple) un mp3 et continuer à partir de là, tout en laissant au système d’exploitation le soin de gérer le processus de restitution de l’audio sur le matériel audio. .
  • L’interprétation alternative est que l’appel fera quelque chose que le programme devra surveiller, mais permettra à la majeure partie du processus de se dérouler en arrière-plan, en ne notifiant le programme qu’à des moments critiques du processus. Par exemple, le fichier asynchrone IO peut être un exemple - le programme fournit au système d'exploitation une mémoire tampon pour écrire dans le fichier et le système d'exploitation avertit le programme uniquement lorsque l'opération est terminée ou qu'une erreur se produit.

Dans les deux cas, l’intention est de permettre au programme de ne pas être bloqué dans l’attente de l’achèvement d’un processus lent. La seule différence réelle réside dans la manière dont le programme devrait réagir. Le terme qui fait référence change également de programmeur à programmeur, de langage en langage ou de plateforme en plateforme. Ou les termes peuvent faire référence à des concepts complètement différents (tels que l’utilisation de synchrone/asynchrone en relation avec la programmation par thread).

Désolé, mais je ne crois pas qu'il existe une seule bonne réponse qui soit globalement vraie.

15
Mac

Un appel non bloquant revient immédiatement avec toutes les données disponibles: le nombre total d'octets demandés, moins ou aucun.

Un appel asynchrone demande un transfert qui sera effectué dans son intégralité (complète) mais se terminera ultérieurement.

13
Koray Tugay

Non bloquant: cette fonction n'attendra pas sur la pile.

Asynchrone: le travail peut continuer pour le compte de l'appel de fonction après que cet appel a quitté la pile

9
Frank Schwieterman

Synchrone est défini comme se produisant au même moment.

Asynchrone est défini comme ne se produisant pas en même temps.

C'est ce qui cause la première confusion. Synchrone est en fait ce que l’on appelle le parallèle. Bien que asynchrone soit séquentiel, faites ceci, puis faites-le.

Maintenant, tout le problème concerne la modélisation d'un comportement asynchrone, car certaines opérations nécessitent la réponse d'une autre avant de pouvoir commencer. C'est donc un problème de coordination. Comment saurez-vous que vous pouvez maintenant démarrer cette opération?

La solution la plus simple est connue sous le nom de blocage.

Blocage est le moment où vous choisissez simplement d'attendre que l'autre chose soit faite et vous retourniez une réponse avant de passer à l'opération qui en avait besoin.

Donc, si vous avez besoin de mettre du beurre sur du pain grillé, vous devez donc d'abord faire griller le pain élevé. La façon dont vous les coordonneriez est que vous feriez d’abord griller le pain élevé, puis de regarder fixement le grille-pain jusqu’à ce qu’il apparaisse, puis de mettre du beurre dessus.

C'est la solution la plus simple et fonctionne très bien. Il n'y a pas de vraie raison de ne pas l'utiliser, à moins que vous ne deviez également faire d'autres choses qui ne nécessitent pas de coordination avec les opérations. Par exemple, faire des plats. Pourquoi attendre sans regarder en regardant le grille-pain, que le pain se lève, alors que vous savez que cela prendra un peu de temps et que vous pourriez laver un plat entier pendant qu'il se termine?

C’est là que deux autres solutions, respectivement non bloquantes et asynchrones, entrent en jeu.

non bloquant, c'est quand vous choisissez de faire d'autres choses sans lien entre vous en attendant que l'opération soit faite. Vérifier la disponibilité de la réponse à votre convenance.

Donc, au lieu de regarder le grille-pain pour qu'il saute. Vous allez laver un plat entier. Et puis, vous jetez un coup d'œil au grille-pain pour voir si les toasts ont sauté. Si ce n’est pas le cas, vous allez laver un autre plat et vérifier au grille-pain entre chaque plat. Quand vous voyez que les toasts ont éclaté, vous arrêtez de faire la vaisselle, vous prenez plutôt les toasts et vous passez au beurre.

Avoir à vérifier constamment les toasts peut être ennuyeux, imaginez que le grille-pain se trouve dans une autre pièce. Entre les assiettes, vous perdez votre temps à vous rendre dans cette autre pièce pour vérifier le pain grillé.

Voici asynchrone.

Asynchrone est le moment où vous choisissez d'effectuer d'autres opérations sans lien entre vous en attendant que l'opération soit effectuée. Au lieu de vérifier cela, vous déléguez le travail de vérification à autre chose, il peut s’agir de l’opération elle-même ou d’un observateur, et vous avez cette notification pour vous informer et éventuellement vous interrompre lorsque la réponse est disponible afin que vous puissiez passer à l’autre opération besoin de ceci.

C'est une terminologie étrange. Cela n’a aucun sens, car toutes ces solutions sont des moyens de créer une coordination asynchrone des tâches dépendantes. C'est pourquoi je préfère l'appeler evented.

Donc, pour celui-ci, vous décidez de mettre à niveau votre grille-pain afin qu'il émette un bip lorsque les toasts sont terminés. Vous écoutez constamment, même lorsque vous faites la vaisselle. En entendant le bip, vous vous souvenez que dès que vous avez terminé de laver votre plat actuel, vous vous arrêtez et allez mettre le beurre sur le pain grillé. Ou vous pouvez choisir d'interrompre le lavage de la parabole actuelle et de gérer le pain grillé immédiatement.

Si vous avez du mal à entendre le bip, vous pouvez demander à votre partenaire de surveiller le grille-pain pour vous et de venir vous dire que le pain est prêt. Votre partenaire peut choisir lui-même l’une des trois stratégies ci-dessus pour coordonner sa tâche consistant à surveiller le grille-pain et à vous dire quand il est prêt.

Pour finir, il est bon de comprendre que même si le non-blocage et l’async (ou ce que je préfère appeler evented) vous permettent de faire d’autres choses pendant que vous attendez, vous ne l’avez pas fait non plus. Vous pouvez choisir de vérifier en permanence l'état d'un appel non bloquant sans rien faire d'autre. C’est souvent pire que de bloquer (par exemple, regarder le grille-pain, puis l’éloigner, puis le regarder jusqu’à ce qu’il soit terminé), de sorte que de nombreuses API non bloquantes vous permettent de passer en mode blocage. Pour evented, vous pouvez simplement attendre inactif jusqu'à ce que vous en soyez informé. L'inconvénient dans ce cas est que l'ajout de la notification était complexe et potentiellement coûteux au départ. Vous deviez acheter un nouveau grille-pain avec fonction bip ou convaincre votre partenaire de le regarder pour vous.

Et encore une chose, vous devez réaliser les compromis fournis par les trois. L'un n'est évidemment pas meilleur que les autres. Pensez à mon exemple. Si votre grille-pain est si rapide, vous n'aurez pas le temps de laver un plat, pas même de commencer à le laver, c'est à quelle vitesse votre grille-pain est. Se lancer sur autre chose dans ce cas n'est qu'une perte de temps et d'effort. Le blocage fera l'affaire. De même, si le lavage d'un plat prend 10 fois plus longtemps que le grillage. Vous devez vous demander ce qui est le plus important à faire. Le pain grillé pourrait devenir froid et dur à ce moment-là, pas la peine, le blocage fera aussi. Ou vous devriez choisir des choses plus rapides à faire pendant que vous attendez. Il y a bien sûr plus, mais ma réponse est déjà longue, je pense que vous devez réfléchir à tout cela et aux complexités de leur mise en œuvre pour décider si cela en vaut la peine et si cela améliorera réellement votre performance ou votre performance.

Edit:

Même si cela est déjà long, je veux aussi qu'il soit complet, donc je vais ajouter deux points supplémentaires.

1) Il existe aussi couramment un quatrième modèle appelé multiplexé. C’est-à-dire que lorsque vous attendez une tâche, vous en démarrez une autre et que vous attendez les deux tâches, vous en démarrez une autre, et ainsi de suite, jusqu’à ce que vous ayez de nombreuses tâches en cours, puis vous attendez au ralenti, mais dans l’ensemble. leur. Donc, dès que tout est fait, vous pouvez traiter sa réponse, puis attendre à nouveau pour les autres. C'est ce qu'on appelle le multiplexage, car pendant que vous attendez, vous devez vérifier chaque tâche l'une après l'autre pour voir si elles sont terminées, jusqu'à ce que l'une d'entre elles soit terminée. C'est un peu une extension au-dessus de la non-blocage normal.

Dans notre exemple, ce serait comme démarrer le grille-pain, puis le lave-vaisselle, puis le micro-ondes, etc. Et ensuite attendre l'un d'entre eux. Où vous voulez vérifier le grille-pain pour voir si c'est fait, sinon vérifier le lave-vaisselle, sinon, le micro-ondes, et encore.

2) Même si je pense que c'est une grosse erreur, synchrone est souvent utilisé pour désigner une chose à la fois. Et asynchrone beaucoup de choses à la fois. Ainsi, vous verrez le blocage synchrone et le non-blocage utilisé pour désigner le blocage et le non-blocage. Et blocage asynchrone et non-blocage utilisé pour désigner multiplexé et événementé.

Je ne comprends pas vraiment comment on en est arrivé là. Mais quand il s'agit de IO et de Calcul, synchrone et asynchrone se réfèrent souvent à ce que l'on appelle mieux non chevauchement et chevauchement. En d'autres termes, asynchrone signifie que IO et Computation se chevauchent, c'est-à-dire qu'ils se produisent simultanément. Bien que synchrone signifie qu'ils ne le sont pas, ils se produisent donc de manière séquentielle. Pour un non-blocage synchrone, cela signifierait que vous ne démarrez pas d'autre IO ou de Calcul, vous êtes simplement occupé à attendre et à simuler un appel bloquant. Je souhaite que les gens arrêtent d'utiliser de manière synchrone et asynchrone comme ça. Donc, je ne l'encourage pas.

5
Didier A.

Blocage appel: le contrôle ne sera renvoyé que lorsque l'appel sera terminé.

non bloquant appel: le contrôle est renvoyé immédiatement. Plus tard, le système d’exploitation signale en quelque sorte au processus que l’appel est terminé.


Synchrone programme: programme qui utilise des appels bloquants . Afin de ne pas geler pendant l'appel, il doit comporter au moins deux threads (c'est pourquoi on l'appelle synchrone - les threads s'exécutent de manière synchrone).

Asynchrone programme: programme qui utilise des appels non bloquants . Il ne peut avoir qu'un seul thread et rester interactif.

2

Ils diffèrent en orthographe seulement. Il n'y a pas de différence dans ce qu'ils se réfèrent. Pour être technique, vous pourriez dire qu'ils diffèrent dans l'accent. Non bloquant fait référence au flux de contrôle (il ne bloque pas.) Asynchrone fait référence au moment où l'événement\data est traité (pas de manière synchrone).

0
stonemetal

Les modèles de blocage nécessitent le blocage de l'application à l'origine du démarrage de l'E/S. Cela signifie qu'il n'est pas possible de chevaucher le traitement et les E/S en même temps. Le modèle synchrone non bloquant autorise un chevauchement du traitement et des E/S, mais il nécessite que l'application vérifie le statut des E/S de manière récurrente. Cela laisse des E/S asynchrones non bloquantes, ce qui permet un chevauchement du traitement et des E/S, y compris la notification de l'achèvement des E/S.

0
P.Gurung