Pour présumer une amélioration de la vitesse due à toute forme de multi-calcul, vous devez présumer soit que plusieurs tâches basées sur le processeur sont exécutées simultanément sur plusieurs ressources informatiques (généralement des cœurs de processeur), soit que toutes les tâches ne reposent pas sur l'utilisation simultanée de la même ressource - c'est-à-dire que certaines tâches peuvent dépendre d'un sous-composant système (stockage sur disque, par exemple) tandis que certaines tâches dépendent d'un autre (réception de la communication d'un périphérique) et d'autres encore peuvent nécessiter l'utilisation de cœurs de processeur.
Le premier scénario est souvent appelé programmation «parallèle». Le second scénario est souvent appelé programmation «simultanée» ou «asynchrone», bien que «simultanée» soit parfois également utilisée pour désigner le cas de la simple autorisation d'un système d'exploitation à entrelacer l'exécution de plusieurs tâches, que cette exécution doive ou non prendre place en série ou si plusieurs ressources peuvent être utilisées pour réaliser une exécution parallèle. Dans ce dernier cas, «concurrent» fait généralement référence à la manière dont l'exécution est écrite dans le programme, plutôt que du point de vue de la simultanéité réelle de l'exécution de la tâche.
Il est très facile de parler de tout cela avec des hypothèses tacites. Par exemple, certains sont prompts à faire une réclamation telle que «Les E / S asynchrones seront plus rapides que les E / S multi-thread». Cette affirmation est douteuse pour plusieurs raisons. Premièrement, il se peut que certains frameworks d'E / S asynchrones soient implémentés précisément avec le multi-threading, auquel cas ils sont un dans le même et cela n'a pas de sens de dire qu'un concept "est plus rapide que" l'autre .
Deuxièmement, même dans le cas où il existe une implémentation à un seul thread d'un framework asynchrone (comme une boucle d'événements à un seul thread), vous devez toujours faire une hypothèse sur ce que fait cette boucle. Par exemple, une chose stupide que vous pouvez faire avec une boucle d'événement à thread unique est de lui demander d'effectuer de manière asynchrone deux tâches différentes purement liées au processeur. Si vous avez fait cela sur une machine avec seulement un cœur de processeur unique idéalisé (en ignorant les optimisations matérielles modernes), l'exécution de cette tâche "asynchrone" ne serait pas vraiment différente de celle avec deux threads gérés indépendamment, ou avec un seul processus - - la différence peut résulter du changement de contexte de thread ou des optimisations de planification du système d'exploitation, mais si les deux tâches vont au CPU, ce serait similaire dans les deux cas.
Il est utile d'imaginer un grand nombre de cas inhabituels ou stupides que vous pourriez rencontrer.
"Asynchrone" ne doit pas nécessairement être simultané, par exemple comme ci-dessus: vous exécutez "de manière asynchrone" deux tâches liées au processeur sur une machine avec exactement un cœur de processeur.
L'exécution multithread n'a pas besoin d'être simultanée: vous créez deux threads sur une machine avec un seul cœur de processeur, ou demandez à deux threads d'acquérir tout autre type de ressource rare (imaginez, par exemple, une base de données réseau qui ne peut en établir qu'une connexion à la fois). L'exécution des threads peut être entrelacée mais le planificateur du système d'exploitation le juge opportun, mais leur durée d'exécution totale ne peut pas être réduite (et sera augmentée à partir du changement de contexte de thread) sur un seul cœur (ou plus généralement, si vous créez plus de threads qu'il n'y en a cœurs pour les exécuter, ou avoir plus de threads demandant une ressource que ce que la ressource peut supporter). Il en va de même pour le multi-traitement.
Ainsi, ni les E / S asynchrones ni le multi-threading ne doivent offrir de gain de performances en termes de temps d'exécution. Ils peuvent même ralentir les choses.
Cependant, si vous définissez un cas d'utilisation spécifique, comme un programme spécifique qui effectue à la fois un appel réseau pour récupérer des données à partir d'une ressource connectée au réseau comme une base de données distante et effectue également des calculs locaux liés au processeur, vous pouvez commencer à raisonner les différences de performances entre les deux méthodes étant donné une hypothèse particulière sur le matériel.
Les questions à se poser: Combien d'étapes de calcul dois-je effectuer et combien de systèmes de ressources indépendants existe-t-il pour les exécuter? Existe-t-il des sous-ensembles d'étapes de calcul qui nécessitent l'utilisation de sous-composants système indépendants et qui peuvent en bénéficier simultanément? Combien de cœurs de processeur ai-je et quelle est la surcharge liée à l'utilisation de plusieurs processeurs ou threads pour effectuer des tâches sur des cœurs séparés?
Si vos tâches reposent largement sur des sous-systèmes indépendants, une solution asynchrone peut être bonne. Si le nombre de threads nécessaires pour le gérer était important, de sorte que le changement de contexte devenait non trivial pour le système d'exploitation, alors une solution asynchrone à thread unique pourrait être meilleure.
Chaque fois que les tâches sont liées par la même ressource (par exemple, plusieurs besoins pour accéder simultanément au même réseau ou à la même ressource locale), le multi-threading introduira probablement une surcharge insatisfaisante, et tandis que l'asynchronie monothread peut introduire moins de surcharge, dans une telle ressource- situation limitée, il ne peut pas non plus produire une accélération. Dans un tel cas, la seule option (si vous voulez une accélération) est de rendre plusieurs copies de cette ressource disponibles (par exemple, plusieurs cœurs de processeur si la ressource rare est le processeur; une meilleure base de données qui prend en charge plus de connexions simultanées si la ressource rare est une base de données à connexion limitée, etc.).
Une autre façon de le dire est: permettre au système d'exploitation d'entrelacer l'utilisation d'une seule ressource pour deux tâches ne peut pas être plus rapide que de simplement laisser une tâche utiliser la ressource pendant que l'autre attend, puis de laisser la deuxième tâche se terminer en série. En outre, le coût de l'entrelacement par l'ordonnanceur signifie que dans toute situation réelle, il crée en fait un ralentissement. Peu importe si l'utilisation entrelacée se produit du processeur, d'une ressource réseau, d'une ressource mémoire, d'un périphérique ou de toute autre ressource système.