Je suis venu ici assez à l'aise avec les deux concepts, mais avec quelque chose qui ne m'est pas clair à leur sujet.
Après avoir lu certaines des réponses, je pense avoir une métaphore correcte et utile pour décrire la différence.
Si vous considérez vos différentes lignes de code comme des cartes à jouer séparées mais ordonnées (arrêtez-moi si j'explique le fonctionnement des cartes perforées à l'ancienne), alors pour chaque procédure distincte écrite, vous aurez une pile unique de cartes (ne copier-coller!) et la différence entre ce qui se passe normalement lorsque vous exécutez du code normalement et de manière asynchrone dépend de votre intérêt ou non.
Lorsque vous exécutez le code, vous remettez au système d'exploitation un ensemble d'opérations uniques (dans lesquelles votre compilateur ou interpréteur a cassé votre code de niveau «supérieur») à transmettre au processeur. Avec un seul processeur, une seule ligne de code peut être exécutée à la fois. Ainsi, afin d'accomplir l'illusion d'exécuter plusieurs processus en même temps, le système d'exploitation utilise une technique dans laquelle il n'envoie au processeur que quelques lignes d'un processus donné à la fois, basculant entre tous les processus en fonction de la façon dont il voit en forme. Le résultat est plusieurs processus montrant la progression de l'utilisateur final à ce qui semble être le même moment.
Pour notre métaphore, la relation est que le système d'exploitation mélange toujours les cartes avant de les envoyer au processeur. Si votre pile de cartes ne dépend pas d'une autre pile, vous ne remarquez pas que votre pile a cessé d'être sélectionnée tandis qu'une autre pile est devenue active. Donc, si vous vous en fichez, cela n'a pas d'importance.
Cependant, si vous vous en souciez (par exemple, il y a plusieurs processus - ou piles de cartes - qui dépendent les uns des autres), alors le brassage du système d'exploitation va bousiller vos résultats.
L'écriture de code asynchrone nécessite la gestion des dépendances entre l'ordre d'exécution, quel que soit cet ordre. C'est pourquoi des constructions comme des "rappels" sont utilisées. Ils disent au processeur, "la prochaine chose à faire est de dire à l'autre pile ce que nous avons fait". En utilisant de tels outils, vous pouvez être assuré que l'autre pile est notifiée avant d'autoriser le système d'exploitation à exécuter plus de ses instructions. ("Si called_back == false: send (no_operation)" - je ne sais pas si c'est réellement ainsi qu'il est implémenté, mais logiquement, je pense que c'est cohérent.)
Pour les processus parallèles, la différence est que vous avez deux piles qui ne se soucient pas l'une de l'autre et deux travailleurs pour les traiter. À la fin de la journée, vous devrez peut-être combiner les résultats des deux piles, ce qui serait alors une question de synchronicité mais, pour l'exécution, vous ne vous en souciez plus.
Je ne sais pas si cela aide, mais je trouve toujours plusieurs explications utiles. Notez également que l'exécution asynchrone n'est pas limitée à un ordinateur individuel et à ses processeurs. D'une manière générale, il s'agit du temps, ou (plus généralement encore) d'un ordre des événements. Donc, si vous envoyez la pile dépendante A au nœud de réseau X et sa pile couplée B à Y, le code asynchrone correct devrait être en mesure de rendre compte de la situation comme s'il s'exécutait localement sur votre ordinateur portable.