Quelle est la différence entre la programmation simultanée et la programmation parallèle? J'ai demandé à Google mais rien trouvé qui m'a aidé à comprendre cette différence. Pourriez-vous me donner un exemple pour les deux?
Pour l'instant j'ai trouvé cette explication: http://www.linux-mag.com/id/7411 - mais "la simultanéité est une propriété du programme" vs "l'exécution en parallèle est une propriété de la machine "Ce n'est pas assez pour moi - je ne peux toujours pas dire ce qui est quoi.
Si votre programme utilise des threads (programmation simultanée), il ne sera pas nécessairement exécuté en tant que tel (exécution parallèle), car cela dépend de la capacité de la machine à gérer plusieurs threads.
Voici un exemple visuel. Discussions sur une machine non-threaded:
-- -- --
/ \
>---- -- -- -- -- ---->>
Discussions sur une machine threaded:
------
/ \
>-------------->>
Les tirets représentent le code exécuté. Comme vous pouvez le constater, ils se séparent et s’exécutent séparément, mais la machine à fileter peut exécuter plusieurs pièces à la fois.
La programmation simultanée concerne les opérations qui semblent se chevaucher et concerne principalement la complexité résultant d'un flux de contrôle non déterministe. Les coûts quantitatifs associés aux programmes concurrents sont généralement à la fois le débit et la latence. Les programmes concurrents sont souvent IO liés mais pas toujours, par exemple. les éboueurs simultanés sont entièrement sur le processeur. L'exemple pédagogique d'un programme simultané est un robot d'indexation Web. Ce programme initie des demandes de pages Web et accepte les réponses simultanément lorsque les résultats des téléchargements deviennent disponibles, accumulant ainsi un ensemble de pages déjà visitées. Le flux de contrôle n'est pas déterministe car les réponses ne sont pas nécessairement reçues dans le même ordre à chaque exécution du programme. Cette caractéristique peut rendre très difficile le débogage de programmes concurrents. Certaines applications sont fondamentalement concurrentes, par exemple Les serveurs Web doivent gérer les connexions clientes simultanément. Erlang , F # flux de travail asynchrones et Scala's Akka sont probablement les bibliothèques les plus prometteuses. approches de la programmation hautement concurrente.
La programmation multicœur est un cas particulier de programmation parallèle. La programmation parallèle concerne les opérations qui se chevauchent dans l'objectif spécifique d'améliorer le débit. On élimine les difficultés de la programmation concurrente en rendant déterministe le flux de contrôle. Généralement, les programmes génèrent des ensembles de tâches enfants qui s'exécutent en parallèle et la tâche parent ne se poursuit qu'une fois que chaque sous-tâche est terminée. Cela rend les programmes parallèles beaucoup plus faciles à déboguer que les programmes concurrents. La partie difficile de la programmation parallèle est l’optimisation des performances en ce qui concerne des problèmes tels que la granularité et la communication. Ce dernier problème reste d'actualité dans le contexte des multicœurs car le transfert de données d'un cache à un autre représente un coût considérable. La multiplication matricielle dense est un exemple pédagogique de la programmation parallèle. Elle peut être résolue efficacement en utilisant l'algorithme Divide-and-Conquer de Straasen et en s'attaquant aux sous-problèmes en parallèle. Cilk est peut-être l'approche la plus prometteuse pour la programmation parallèle hautes performances sur multicœurs et a été adoptée à la fois par Intel Threaded Building Blocks et Microsoft Task Parallel Library (en .NET 4).
https://joearms.github.io/published/2013-04-05-concurrent-and-parallel-programming.html
Concurrent = Deux files d'attente et une machine à café.
Parallèle = Deux files d'attente et deux machines à café.
Interprétation de la question initiale comme un calcul parallèle/simultané au lieu de la programmation .
Dans calcul simultané, deux calculs sont avancés indépendamment l'un de l'autre. Le second calcul n'a pas à attendre que le premier soit terminé pour avancer. Cependant, il ne dit pas comment cela est réalisé. Dans une configuration monocœur, il est nécessaire de suspendre et d'alterner entre les threads (également appelé multithreading préventif ).
Dans le calcul parallèle , deux calculs avancent simultanément - c'est-à-dire littéralement au même moment. Cela n’est pas possible avec un seul processeur et nécessite plutôt une configuration multicœur.
contre
Selon: "Parallel vs Concurrent in Node.js" .
Dans la vue d'un processeur, il peut être décrit par cette image
Dans la vue d'un processeur, il peut être décrit par cette image
Je crois que la programmation simultanée fait référence à la programmation multithread, qui consiste à laisser votre programme exécuter plusieurs threads, sans se soucier des détails matériels.
La programmation parallèle fait référence à la conception spécifique de vos algorithmes de programme pour tirer parti de l'exécution parallèle disponible. Par exemple, vous pouvez exécuter en parallèle deux branches de certains algorithmes en espérant obtenir le résultat plus tôt (en moyenne) que si vous aviez d'abord vérifié la première, puis la seconde.
J'ai trouvé ce contenu dans certains blogs. Je pensais que c'était utile et pertinent.
La concurrence et le parallélisme ne sont pas la même chose. Deux tâches T1 et T2 sont simultanées si l'ordre dans lequel les deux tâches sont exécutées dans le temps n'est pas prédéterminé,
T1 peut être exécuté et terminé avant T2, T2 peut être exécuté et terminé avant T1, T2 et T2 peuvent être exécutés simultanément à la même instance de temps (parallélisme), T1 et T2 peuvent être exécutés alternativement, ... Si deux threads simultanés sont planifiés par le système d'exploitation pour s'exécuter sur un processeur monocœur non-SMT ni CMP, vous pouvez obtenir la simultanéité, mais pas le parallélisme. Le parallélisme est possible sur des systèmes multi-core, multi-processeurs ou distribués.
La simultanéité est souvent qualifiée de propriété d'un programme et est un concept plus général que le parallélisme.
Source: https://blogs.Oracle.com/yuanlin/entry/concurrency_vs_parallelism_concurrent_programming
Ce sont deux phrases qui décrivent la même chose de points de vue (très légèrement) différents. La programmation parallèle décrit la situation du point de vue du matériel: il existe au moins deux processeurs (éventuellement dans un même package physique) qui traitent un problème en parallèle. La programmation simultanée décrit davantage les choses du point de vue du logiciel - deux actions ou plus peuvent se produire exactement au même moment (simultanément).
Le problème ici est que les gens essaient d'utiliser les deux expressions pour établir une distinction claire lorsqu'il n'en existe aucune. La réalité est que la ligne de démarcation qu'ils tentent de tracer est floue et indistincte depuis des décennies et s'est progressivement accentuée au fil du temps.
Ce qu’ils essaient de dire, c’est qu’autrefois, la plupart des ordinateurs n’avaient qu’un seul processeur. Lorsque vous exécutez plusieurs processus (ou threads) sur cette CPU unique, celle-ci n'exécutait en réalité qu'une instruction à la fois. L’apparence de la simultanéité était une illusion - la CPU basculait entre des instructions d’exécution de différents threads assez rapidement pour que la perception humaine (pour laquelle tout ce qui est inférieur à 100 ms semblerait instantané) semblait donner l’impression de faire beaucoup de choses en même temps.
Le contraste évident avec ceci est un ordinateur avec plusieurs processeurs, ou un processeur avec plusieurs cœurs, de sorte que la machine exécute des instructions à partir de plusieurs threads et/ou processus au même moment; le code qui en exécute un ne peut/n’a aucun effet sur le code qui s’exécute dans l’autre.
Maintenant le problème: une distinction aussi nette a presque jamais existé. Les concepteurs informatiques sont en fait assez intelligents. Ils ont donc remarqué depuis longtemps (par exemple) que, lorsque vous deviez lire des données à partir d’un périphérique d’E/S tel qu’un disque, il fallait un long temps temps (en termes de cycles du processeur) pour terminer. Au lieu de laisser la CPU inactive pendant que cela se produisait, ils ont découvert différentes façons de permettre à un processus/thread de faire une demande d'E/S et de laisser le code d'un autre processus/thread s'exécuter sur la CPU pendant que la demande d'E/S était terminée.
Ainsi, bien avant que les CPU multicœurs ne deviennent la norme, nous avions des opérations à partir de plusieurs threads se déroulant en parallèle.
Ce n'est que la partie visible de l'iceberg. Il y a des décennies, les ordinateurs ont également commencé à fournir un autre niveau de parallélisme. Encore une fois, étant des personnes assez intelligentes, les concepteurs informatiques ont remarqué que dans de nombreux cas, ils avaient des instructions qui ne s’affectaient pas entre elles. Il était donc possible d’exécuter plus d’une instruction du même flux en même temps. Le Control Data 6600 est l’un des premiers exemples qui soit devenu assez connu. C’était (de loin) l’ordinateur le plus rapide au monde lors de son introduction en 1964 - et une grande partie de la même architecture de base reste utilisée de nos jours. Il suivait les ressources utilisées par chaque instruction et disposait d'un ensemble d'unités d'exécution qui exécutaient les instructions dès que les ressources dont elles dépendaient devenaient disponibles, ce qui est très similaire à la conception des processeurs Intel/AMD les plus récents.
Mais (comme le disaient les publicités), attendez, ce n'est pas tout. Il y a encore un autre élément de design à ajouter à la confusion. On lui a donné plusieurs noms différents (par exemple, "Hyperthreading", "SMT", "CMP"), mais ils font tous référence à la même idée de base: un processeur capable d'exécuter plusieurs threads simultanément, en utilisant une combinaison de ressources sont indépendants pour chaque thread et certaines ressources partagées entre les threads. Dans un cas typique, cela est combiné au parallélisme au niveau instruction décrit ci-dessus. Pour ce faire, nous avons deux (ou plus) ensembles de registres architecturaux. Ensuite, nous avons un ensemble d’unités d’exécution capables d’exécuter des instructions dès que les ressources nécessaires sont disponibles. Celles-ci se combinent souvent bien car les instructions provenant de flux distincts ne dépendent pratiquement jamais des mêmes ressources.
Ensuite, bien sûr, nous arrivons aux systèmes modernes à plusieurs cœurs. Ici, les choses sont évidentes, non? Nous avons N (quelque part entre 2 et 256, pour le moment) des cœurs séparés, qui peuvent tous exécuter des instructions en même temps, nous avons donc un cas précis de parallélisme réel - exécuter des instructions dans un processus/thread ne ' t affecter l'exécution d'instructions dans un autre.
Eh bien, en quelque sorte. Même dans ce cas, nous avons des ressources indépendantes (registres, unités d’exécution, au moins un niveau de cache) et des ressources partagées (généralement au moins le niveau de cache le plus bas, et bien sûr les contrôleurs de mémoire et la bande passante vers la mémoire).
En résumé: les scénarios simples que les gens aiment à opposer entre ressources partagées et ressources indépendantes ne se produisent pratiquement jamais dans la vie réelle. Avec toutes les ressources partagées, nous nous retrouvons avec quelque chose comme MS-DOS, dans lequel nous ne pouvons exécuter qu'un programme à la fois, et nous devons cesser d'en exécuter un avant de pouvoir exécuter l'autre. Avec des ressources complètement indépendantes, nous avons N ordinateurs qui exécutent MS-DOS (sans même un réseau pour les connecter) sans aucune possibilité de partager quoi que ce soit entre eux (car si nous pouvons même partager un fichier, eh bien, il s’agit d’une ressource partagée, une violation du principe de base selon lequel rien ne doit être partagé).
Chaque cas intéressant implique une combinaison de ressources indépendantes et de ressources partagées. Chaque ordinateur raisonnablement moderne (et beaucoup qui ne le sont pas du tout) a au moins une certaine capacité à effectuer simultanément au moins quelques opérations indépendantes, et à peu près tout ce qui est plus sophistiqué que MS-DOS en a profité pour au moins Un certain degré.
La distinction claire et nette entre "concurrent" et "parallèle" que les gens aiment dessiner n’existe tout simplement pas et n’existe presque jamais. Ce que les gens aiment classer comme "simultané" implique généralement toujours au moins un, et souvent plus, de types différents d'exécution parallèle. Ce qu'ils aiment classer comme "parallèle" implique souvent le partage de ressources et (par exemple) un processus bloquant l'exécution d'un autre tout en utilisant une ressource partagée entre les deux.
Les personnes qui tentent d'établir une distinction nette entre "parallèle" et "concurrent" vivent dans un fantasme d'ordinateur qui n'a jamais existé.
La planification classique des tâches peut être en série , en parallèle ou simultané .
Serial : les tâches doivent être exécutées les unes après les autres dans un ordre trompé connu, sinon cela ne fonctionnera pas. Assez facile.
Parallèle : les tâches doivent être exécutées en même temps, sinon cela ne fonctionnera pas.
Essayez d'éviter cela ou nous aurons des larmes à l'heure du thé.
Concurrent : on s'en fiche. Nous ne sommes cependant pas négligents: nous l'avons analysé et cela n'a pas d'importance; nous pouvons donc exécuter n'importe quelle tâche en utilisant n'importe quelle installation disponible à tout moment. Jours heureux.
Souvent, la planification disponible change lors d'événements connus que nous appelons un changement d'état.
Les gens pensent souvent qu’il s’agit d’un logiciel, mais c’est en fait un concept de conception de système qui date d’avant les ordinateurs; Les systèmes logiciels ont été un peu lents, très peu de langages logiciels ont même tenté de résoudre le problème. Vous pouvez essayer de chercher le langage transputer occam si vous êtes intéressé.
En résumé, la conception des systèmes aborde les points suivants:
Bonne chance.
En programmation, la simultanéité est la composition de processus exécutant indépendamment, tandis que le parallélisme est l'exécution simultanée de calculs (éventuellement liés).
- Andrew Gerrand -
Et
La simultanéité est la composition de calculs exécutés indépendamment. La simultanéité est un moyen de structurer un logiciel, en particulier comme un moyen d’écrire du code propre qui interagit bien avec le monde réel. Ce n'est pas un parallélisme.
La simultanéité n’est pas un parallélisme, bien qu’elle permette le parallélisme. Si vous n'avez qu'un seul processeur, votre programme peut toujours être concurrent mais ne peut pas être parallèle. D'autre part, un programme concurrent bien écrit peut s'exécuter efficacement en parallèle sur un multiprocesseur. Cette propriété pourrait être importante ...
- Rob Pike -
Pour comprendre la différence, je vous recommande fortement de voir cette vidéo de Rob Pike (l'un des créateurs de Golang). La simultanéité n'est pas un parallélisme
La programmation parallèle se produit lorsque le code est exécuté en même temps et que chaque exécution est indépendante de l'autre. Par conséquent, les variables partagées ne sont généralement pas une source de préoccupation, car cela ne se produira probablement pas.
Cependant, la programmation simultanée consiste à exécuter du code par différents processus/threads partageant des variables. Par conséquent, sur la programmation simultanée, nous devons établir une sorte de règle pour décider quel processus/thread s'exécute en premier. sera la cohérence et que nous pouvons savoir avec certitude ce qui va se passer. S'il n'y a pas de contrôle et que tous les threads calculent en même temps et stockent des choses sur les mêmes variables, comment pourrions-nous savoir à quoi s'attendre à la fin? Peut-être qu'un thread est plus rapide qu'un autre, peut-être même l'un des threads s'est-il arrêté au milieu de son exécution et un autre a poursuivi un calcul différent avec une variable corrompue (pas encore totalement calculée), les possibilités sont infinies. C'est dans ces situations que nous utilisons généralement une programmation concurrente plutôt que parallèle.
Concurrent programming
est un sens général qui fait référence aux environnements dans lesquels les tâches que nous définissons peuvent se dérouler dans n'importe quel ordre. Une tâche peut se dérouler avant ou après une autre et certaines ou toutes les tâches peuvent être exécutées simultanément.
Parallel programming
doit faire spécifiquement référence à l'exécution simultanée de tâches simultanées sur différents processeurs. Ainsi, toute la programmation parallèle est simultanée, mais toutes les programmations simultanées ne sont pas parallèles.
Source: PThreads Programming - Un standard POSIX pour un meilleur multitraitement, Buttlar, Farrell, Nichols
J'ai compris la différence d'être:
1) Concurrent - exécution en tandem à l'aide de ressources partagées 2) Parallèle - exécution côte à côte avec des ressources différentes
Ainsi, vous pouvez avoir deux événements simultanés indépendants l'un de l'autre, même s'ils se rejoignent aux points (2) ou deux éléments faisant partie des mêmes réserves tout au long des opérations en cours d'exécution (1).
Bien qu'il n'y ait pas d'accord complet sur la distinction entre les termes parallèle et simultané , de nombreux auteurs font les distinctions suivantes:
Les programmes parallèles sont donc simultanés, mais un programme tel qu'un système d'exploitation multitâche est également concurrent, même lorsqu'il est exécuté sur une machine avec un seul cœur, car plusieurs tâches peuvent être en cours à tout moment.
Source: Une introduction à la programmation parallèle, Peter Pacheco
Concurrence et parallélisme Source
Dans un processus multithread sur un seul processeur, le processeur peut permuter les ressources d'exécution entre les threads, ce qui entraîne une exécution simultanée .
Dans le même processus multithread dans un environnement multiprocesseur à mémoire partagée, chaque thread du processus peut s'exécuter simultanément sur un processeur séparé, ce qui entraîne une exécution parallèle .
Lorsque le processus compte moins ou autant de threads qu'il y a de processeurs, les systèmes de support de threads associés à l'environnement d'exploitation garantissent que chaque thread s'exécute sur un processeur différent.
Par exemple, dans une multiplication de matrice comportant le même nombre de threads et de processeurs, chaque thread (et chaque processeur) calcule une ligne du résultat.
Différentes personnes parlent de différents types de concurrence et de parallélisme dans de nombreux cas spécifiques, de sorte que certaines abstractions sont nécessaires pour couvrir leur nature commune.
L'abstraction de base est faite en informatique, où la simultanéité et le parallélisme sont attribués aux propriétés de programmes . Ici, les programmes sont des descriptions formalisées de l'informatique. Ces programmes ne doivent pas nécessairement être dans un langage ou un codage particulier, qui est spécifique à la mise en œuvre. L'existence d'API/ABI/ISA/OS n'est pas pertinente pour un tel niveau d'abstraction. Il faudra sûrement une connaissance plus détaillée de l’implémentation (telle que le modèle de threading) pour effectuer des travaux de programmation concrets. L’esprit de l’abstraction de base n’a pas changé.
Un deuxième fait important est que, en tant que propriétés générales, la concurrence et le parallélisme peuvent coexister dans de nombreuses abstractions différentes .
Pour la distinction générale, voir le réponse pertinente pour la vue de base de la simultanéité par rapport au parallélisme. (Il y a aussi des liens contenant des sources supplémentaires.)
La programmation simultanée et la programmation parallèle sont des techniques permettant de mettre en œuvre de telles propriétés générales avec certains systèmes, ce qui expose la possibilité de programmation. Les systèmes sont généralement des langages de programmation et leurs implémentations.
Un langage de programmation peut exposer les propriétés voulues par des règles sémantiques intégrées. Dans la plupart des cas, ces règles spécifient les évaluations de structures de langage spécifiques (par exemple, des expressions), ce qui rend le calcul impliqué réellement simultané ou parallèle. (Plus précisément, les effets de calcul impliqués par les évaluations peuvent parfaitement refléter ces propriétés.) Cependant, la sémantique simultanée/parallèle des langages est essentiellement complexe et n'est pas nécessaire aux travaux pratiques (pour mettre en œuvre des algorithmes efficaces simultanés/parallèles comme solutions de problèmes réalistes ). Ainsi, la plupart des langages traditionnels adoptent une approche plus conservatrice et plus simple: assumer la sémantique de l'évaluation totalement séquentielle et sérielle, puis fournir des primitives optionnelles pour permettre à some des calculs étant simultanés et parallèles. Ces primitives peuvent être des mots-clés ou des constructions procédurales ("fonctions") supportées par le langage. Ils sont implémentés en fonction de l’interaction avec les environnements hébergés (système d’exploitation ou interface matérielle "bare metal"), généralement opaques (ne pouvant être dérivés à l’aide du langage utilisé de manière portable). Ainsi, dans ce type particulier d'abstractions de haut niveau vues par les programmeurs, rien n'est concurrent/parallèle en dehors de ces primitives "magiques" et des programmes reposant sur ces primitives; les programmeurs peuvent alors profiter d'une expérience de programmation moins sujette aux erreurs lorsque les propriétés de concurrence/parallélisme ne sont pas aussi intéressées.
Bien que les primitives abstiennent le complexe dans les abstractions les plus élevées, les implémentations ont toujours la complexité supplémentaire que ne présente pas la fonctionnalité de langage. Des abstractions de niveau moyen sont donc nécessaires. Un exemple typique est threading . Les threads permettent à un ou plusieurs thread d'exécution (ou simplement thread ; parfois, il est également appelé processus , qui n'est pas nécessairement le concept d'une tâche planifiée dans un système d'exploitation) pris en charge par l'implémentation du langage (le moteur d'exécution). Les threads sont généralement planifiés de manière préemptive par le moteur d'exécution, de sorte qu'un thread ne doit rien savoir des autres threads. Ainsi, les threads sont naturels pour implémenter le parallélisme tant qu'ils ne partagent rien (les ressources critiques ): décomposez simplement les calculs dans différents threads, une fois que l'implémentation sous-jacente permet le chevauchement des ressources de calcul pendant l'exécution, ça marche. Les threads sont également soumis à des accès simultanés à des ressources partagées: un simple accès aux ressources dans n'importe quel ordre respecte les contraintes minimales requises par l'algorithme, et la mise en œuvre finira par déterminer le moment de l'accès. Dans ce cas, certaines opérations de synchronisation peuvent être nécessaires. Certaines langues traitent les opérations de threading et de synchronisation comme des parties de l'abstraction de haut niveau et les exposent en tant que primitives, tandis que d'autres langues n'encouragent que des primitives de plus haut niveau (comme futures/promises ).
Au niveau des threads spécifiques à la langue, il existe plusieurs tâches de l'environnement d'hébergement sous-jacent (généralement un système d'exploitation). Le multitâche préemptif au niveau du système d'exploitation est utilisé pour implémenter le multithreading (préemptif). Dans certains environnements tels que Windows NT, les unités de planification de base (les tâches) sont également des "threads". Pour les différencier avec l'implémentation dans l'espace utilisateur des threads mentionnés ci-dessus, ils sont appelés threads du noyau, où "noyau" désigne le noyau du système d'exploitation. (cependant, à proprement parler, ce n'est pas tout à fait vrai pour Windows NT; le "vrai" noyau est l'exécutif NT). Les threads du noyau ne sont pas toujours mappés 1: 1 sur les threads de l'espace utilisateur, bien que le mappage 1: 1 réduise souvent la majeure partie des coûts liés au mappage. Puisque les threads du noyau sont lourds (impliquant des appels système) pour créer/détruire/communiquer, il n’existe pas 1: 1 threads verts dans l’espace utilisateur pour surmonter les problèmes de surcharge au détriment de la surcharge de mappage. Le choix de la cartographie en fonction du paradigme de programmation attendu dans l'abstraction de haut niveau. Par exemple, lorsqu'un très grand nombre de threads de l'espace utilisateur doivent être exécutés simultanément (comme Erlang ), le mappage 1: 1 n'est jamais réalisable.
Le sous-jacent du multitâche du système d'exploitation est un multitâche au niveau ISA fourni par le noyau logique du processeur. Il s’agit généralement de l’interface publique la plus basse pour les programmeurs. Sous ce niveau, il peut exister SMT . Il s'agit d'une forme de multithreading plus bas implémenté par le matériel, mais peut-être encore quelque peu programmable, même si elle n'est généralement accessible que par le fabricant du processeur. Notez que la conception matérielle reflète apparemment le parallélisme, mais il existe également un mécanisme de planification simultané pour que les ressources matérielles internes soient utilisées efficacement.
Dans chaque niveau de "threading" mentionné ci-dessus, la simultanéité et le parallélisme sont impliqués. Bien que les interfaces de programmation varient considérablement, elles sont toutes soumises aux propriétés révélées par l’abstraction de base au tout début.