Concurrence vs parallélisme

La simultanéité et le parallélisme sont utilisés en relation avec les programmes multithread, mais il y a beaucoup de confusion sur la similitude et la différence entre eux. La grande question à cet égard: le parallélisme de concurrence est-il ou non? Bien que les deux termes semblent assez similaires, mais que la réponse à la question ci-dessus soit NON, la concurrence et le parallélisme ne sont pas les mêmes. Maintenant, s'ils ne sont pas les mêmes, quelle est la différence fondamentale entre eux?

En termes simples, la concurrence traite de la gestion de l'accès à l'état partagé à partir de différents threads et de l'autre côté, le parallélisme traite de l'utilisation de plusieurs processeurs ou de ses cœurs pour améliorer les performances du matériel.

Concurrence en détail

La concurrence se produit lorsque deux tâches se chevauchent lors de l'exécution. Il peut s'agir d'une situation où une application progresse sur plus d'une tâche à la fois. Nous pouvons le comprendre schématiquement; plusieurs tâches progressent en même temps, comme suit -

Niveaux de concurrence

Dans cette section, nous aborderons les trois niveaux importants de concurrence en termes de programmation -

Concurrence de bas niveau

Dans ce niveau de concurrence, il y a une utilisation explicite des opérations atomiques. Nous ne pouvons pas utiliser ce type de concurrence pour la création d'applications, car il est très sujet aux erreurs et difficile à déboguer. Même Python ne prend pas en charge ce type de concurrence.

Concurrence de niveau intermédiaire

Dans cette concurrence, il n'y a pas d'utilisation d'opérations atomiques explicites. Il utilise les verrous explicites. Python et d'autres langages de programmation prennent en charge ce type de concurrence. La plupart des programmeurs d'applications utilisent cette concurrence.

Concurrence de haut niveau

Dans cette concurrence, ni les opérations atomiques explicites ni les verrous explicites ne sont utilisés. Python aconcurrent.futures module pour prendre en charge ce type de concurrence.

Propriétés des systèmes concurrents

Pour qu'un programme ou un système concurrent soit correct, certaines propriétés doivent être satisfaites par celui-ci. Les propriétés liées à la terminaison du système sont les suivantes -

Propriété d'exactitude

La propriété d'exactitude signifie que le programme ou le système doit fournir la bonne réponse souhaitée. Pour faire simple, nous pouvons dire que le système doit correctement mapper l'état du programme de départ à l'état final.

Propriété de sécurité

La propriété de sécurité signifie que le programme ou le système doit rester dans un “good” ou “safe” état et ne fait jamais rien “bad”.

Propriété vivante

Cette propriété signifie qu'un programme ou un système doit “make progress” et il atteindrait un état souhaitable.

Acteurs de systèmes concurrents

Il s'agit d'une propriété commune du système concurrent dans lequel il peut y avoir plusieurs processus et threads, qui s'exécutent en même temps pour progresser sur leurs propres tâches. Ces processus et threads sont appelés acteurs du système concurrent.

Ressources des systèmes concurrents

Les acteurs doivent utiliser les ressources telles que la mémoire, le disque, l'imprimante, etc. afin d'accomplir leurs tâches.

Certains ensembles de règles

Chaque système concurrent doit posséder un ensemble de règles pour définir le type de tâches à effectuer par les acteurs et le calendrier de chacune. Les tâches peuvent être l'acquisition de verrous, le partage de mémoire, la modification de l'état, etc.

Obstacles des systèmes concurrents

Lors de la mise en œuvre de systèmes concurrents, le programmeur doit prendre en considération les deux problèmes importants suivants, qui peuvent être les barrières des systèmes concurrents:

Partage de données

Un problème important lors de la mise en œuvre des systèmes simultanés est le partage des données entre plusieurs threads ou processus. En fait, le programmeur doit s'assurer que les verrous protègent les données partagées afin que tous les accès à celles-ci soient sérialisés et qu'un seul thread ou processus puisse accéder aux données partagées à la fois. Dans le cas où plusieurs threads ou processus essaient tous d'accéder aux mêmes données partagées, tous, mais au moins un d'entre eux, ne seraient pas bloqués et resteraient inactifs. En d'autres termes, nous pouvons dire que nous ne pourrions utiliser qu'un seul processus ou thread à la fois lorsque le verrouillage est en vigueur. Il peut y avoir des solutions simples pour supprimer les barrières mentionnées ci-dessus -

Restriction de partage de données

La solution la plus simple consiste à ne partager aucune donnée modifiable. Dans ce cas, nous n'avons pas besoin d'utiliser le verrouillage explicite et la barrière de concurrence due aux données mutuelles serait résolue.

Aide à la structure des données

Plusieurs fois, les processus simultanés doivent accéder aux mêmes données en même temps. Une autre solution, que l'utilisation de verrous explicites, consiste à utiliser une structure de données qui prend en charge l'accès simultané. Par exemple, nous pouvons utiliser lequeuemodule, qui fournit des files d'attente thread-safe. Nous pouvons également utilisermultiprocessing.JoinableQueue classes pour l'accès concurrentiel basé sur le multitraitement.

Transfert de données immuable

Parfois, la structure de données que nous utilisons, disons la file d'attente d'accès concurrentiel, ne convient pas, nous pouvons alors transmettre les données immuables sans les verrouiller.

Transfert de données mutable

Dans le prolongement de la solution ci-dessus, supposons que s'il est nécessaire de ne transmettre que des données modifiables, plutôt que des données immuables, nous pouvons alors transmettre des données mutables en lecture seule.

Partage des ressources d'E / S

Un autre problème important dans l'implémentation de systèmes simultanés est l'utilisation des ressources d'E / S par des threads ou des processus. Le problème survient lorsqu'un thread ou un processus utilise les E / S pendant si longtemps et qu'un autre est inactif. Nous pouvons voir ce type de barrière tout en travaillant avec une application lourde d'E / S. Il peut être compris à l'aide d'un exemple, la demande de pages à partir d'un navigateur Web. C'est une application lourde. Ici, si la vitesse à laquelle les données sont demandées est plus lente que la vitesse à laquelle elles sont consommées, alors nous avons une barrière d'E / S dans notre système concurrent.

Le script Python suivant permet de demander une page Web et d'obtenir le temps que notre réseau a mis pour obtenir la page demandée -

import urllib.request

import time

ts = time.time()

req = urllib.request.urlopen('http://www.tutorialspoint.com')

pageHtml = req.read()

te = time.time()

print("Page Fetching Time : {} Seconds".format (te-ts))

Après avoir exécuté le script ci-dessus, nous pouvons obtenir le temps de récupération de la page comme indiqué ci-dessous.

Production

Page Fetching Time: 1.0991398811340332 Seconds

Nous pouvons voir que le temps de récupération de la page est supérieur à une seconde. Maintenant, que se passe-t-il si nous voulons récupérer des milliers de pages Web différentes, vous pouvez comprendre combien de temps notre réseau prendrait.

Qu'est-ce que le parallélisme?

Le parallélisme peut être défini comme l'art de diviser les tâches en sous-tâches pouvant être traitées simultanément. C'est le contraire de la concurrence, comme indiqué ci-dessus, dans laquelle deux événements ou plus se produisent en même temps. Nous pouvons le comprendre schématiquement; une tâche est divisée en un certain nombre de sous-tâches qui peuvent être traitées en parallèle, comme suit -

Pour avoir plus d'idées sur la distinction entre la concurrence et le parallélisme, considérez les points suivants -

Concurrent mais pas parallèle

Une application peut être concurrente mais pas parallèle signifie qu'elle traite plus d'une tâche à la fois, mais les tâches ne sont pas divisées en sous-tâches.

Parallèle mais pas simultané

Une application peut être parallèle mais pas concurrente signifie qu'elle ne fonctionne que sur une tâche à la fois et que les tâches décomposées en sous-tâches peuvent être traitées en parallèle.

Ni parallèle ni simultané

Une application ne peut être ni parallèle ni concurrente. Cela signifie qu'il ne fonctionne que sur une seule tâche à la fois et que la tâche n'est jamais divisée en sous-tâches.

Parallèle et simultané

Une application peut être à la fois parallèle et simultanée, ce qui signifie qu'elle fonctionne à la fois sur plusieurs tâches à la fois et que la tâche est divisée en sous-tâches pour les exécuter en parallèle.

Nécessité du parallélisme

Nous pouvons réaliser le parallélisme en répartissant les sous-tâches entre différents cœurs d'un seul processeur ou entre plusieurs ordinateurs connectés au sein d'un réseau.

Considérez les points importants suivants pour comprendre pourquoi il est nécessaire de réaliser le parallélisme -

Exécution de code efficace

Avec l'aide du parallélisme, nous pouvons exécuter notre code efficacement. Cela nous fera gagner du temps car le même code en parties s'exécute en parallèle.

Plus rapide que l'informatique séquentielle

Le calcul séquentiel est limité par des facteurs physiques et pratiques en raison desquels il n'est pas possible d'obtenir des résultats de calcul plus rapides. D'autre part, ce problème est résolu par le calcul parallèle et nous donne des résultats de calcul plus rapides que le calcul séquentiel.

Moins de temps d'exécution

Le traitement parallèle réduit le temps d'exécution du code du programme.

Si nous parlons d'exemple réel de parallélisme, la carte graphique de notre ordinateur est l'exemple qui met en évidence la véritable puissance du traitement parallèle car elle possède des centaines de cœurs de traitement individuels qui fonctionnent indépendamment et peuvent effectuer l'exécution en même temps. Pour cette raison, nous sommes également en mesure d'exécuter des applications et des jeux haut de gamme.

Compréhension des processeurs pour la mise en œuvre

Nous connaissons la concurrence, le parallélisme et la différence entre eux, mais qu'en est-il du système sur lequel il doit être implémenté. Il est très nécessaire d'avoir la compréhension du système, sur lequel nous allons mettre en œuvre, car cela nous donne l'avantage de prendre des décisions éclairées lors de la conception du logiciel. Nous avons les deux types de processeurs suivants -

Processeurs monocœur

Les processeurs monocœur sont capables d'exécuter un thread à tout moment. Ces processeurs utilisentcontext switchingpour stocker toutes les informations nécessaires pour un thread à un moment précis, puis restaurer les informations ultérieurement. Le mécanisme de changement de contexte nous aide à progresser sur un certain nombre de threads en une seconde donnée et il semble que le système travaille sur plusieurs choses.

Les processeurs monocœur présentent de nombreux avantages. Ces processeurs nécessitent moins d'énergie et il n'y a pas de protocole de communication complexe entre plusieurs cœurs. D'autre part, la vitesse des processeurs monocœur est limitée et ne convient pas aux applications plus importantes.

Processeurs multicœurs

Les processeurs multicœurs ont plusieurs unités de traitement indépendantes également appelées cores.

Ces processeurs n'ont pas besoin de mécanisme de changement de contexte car chaque cœur contient tout ce dont il a besoin pour exécuter une séquence d'instructions stockées.

Cycle d'extraction-décodage-exécution

Les cœurs des processeurs multicœurs suivent un cycle d'exécution. Ce cycle s'appelle leFetch-Decode-Executecycle. Cela implique les étapes suivantes -

Récupérer

C'est la première étape du cycle, qui implique la récupération des instructions de la mémoire du programme.

Décoder

Les instructions récemment récupérées seraient converties en une série de signaux qui déclencheront d'autres parties du processeur.

Exécuter

C'est la dernière étape dans laquelle les instructions extraites et décodées seraient exécutées. Le résultat de l'exécution sera stocké dans un registre CPU.

Un avantage ici est que l'exécution dans les processeurs multicœurs est plus rapide que celle des processeurs monocœur. Il convient aux applications plus importantes. D'autre part, un protocole de communication complexe entre plusieurs cœurs est un problème. Les cœurs multiples nécessitent plus de puissance que les processeurs monocœur.