La CPU (son contrôleur de mémoire en particulier) peut tirer parti du fait que la mémoire n'est pas mutée
L' avantage est, ce fait permet d' économiser compilateur d'utiliser membar instructions lorsque les données sont accessibles.
Une barrière de mémoire, également connue sous le nom de membre, instruction de barrière de mémoire ou clôture, est un type d'instruction de barrière qui oblige une unité centrale de traitement ou un compilateur à appliquer une contrainte d'ordre aux opérations de mémoire émises avant et après l'instruction de barrière. Cela signifie généralement que certaines opérations sont garanties avant la barrière et d’autres après.
Les barrières de mémoire sont nécessaires car la plupart des processeurs modernes utilisent des optimisations de performances pouvant entraîner une exécution dans le désordre. Cette réorganisation des opérations de mémoire (charges et magasins) passe normalement inaperçue au sein d'un seul thread d'exécution, mais peut entraîner un comportement imprévisible dans les programmes et les pilotes de périphériques concurrents, à moins d'être soigneusement contrôlée ...
Vous voyez, lorsque les données sont accédées à partir de différents threads, sur un processeur multicœur, la procédure est la suivante: différents threads s'exécutent sur des cœurs différents, chacun utilisant son propre cache (local par rapport à son cœur) - une copie d'un cache global.
Si les données sont modifiables et que le programmeur a besoin d’être cohérentes entre les différents threads, des mesures doivent être prises pour garantir la cohérence. Pour le programmeur, cela signifie qu’il faut utiliser des constructions de synchronisation lorsqu’il accède (par exemple, en lecture) aux données d’un thread particulier.
Pour le compilateur, la construction de synchronisation dans le code signifie qu'il doit insérer une instruction membar afin de s'assurer que les modifications apportées à la copie des données sur l'un des cœurs sont correctement propagées ("publié"), afin de garantir que les caches des autres cœurs avoir la même copie (à jour).
Pour simplifier un peu, voir la note ci - dessous , voici ce qui se passe sur un processeur multicœur pour les membres:
- Tous les cœurs arrêtent le traitement - pour éviter d'écrire accidentellement dans le cache.
- Toutes les mises à jour apportées aux caches locaux sont réécrites dans une sauvegarde globale - afin de garantir que le cache global contient les données les plus récentes. Cela prend du temps.
- Les données mises à jour sont réécrites du cache global vers les emplacements locaux - afin de garantir que les caches locaux contiennent les données les plus récentes. Cela prend du temps.
- Tous les cœurs reprennent l'exécution.
Vous voyez, tous les cœurs ne font rien pendant la copie des données entre les caches globaux et locaux . Cela est nécessaire pour garantir que les données mutables sont correctement synchronisées (thread-safe). S'il y a 4 cœurs, les 4 s'arrêtent et attendent pendant la synchronisation des caches. S'il y en a 8, les 8 s'arrêtent. S'il y a 16 ... eh bien, vous avez 15 cœurs qui ne font rien exactement en attendant les tâches nécessaires à l'une de ces tâches.
Voyons maintenant ce qui se passe lorsque les données sont immuables. Peu importe le fil qui y accède, il est garanti que ce sera la même chose. Pour les programmeurs, cela signifie qu'il n'est pas nécessaire d'insérer des constructions de synchronisation lorsqu'ils accèdent à des données (en lecture) dans un thread particulier.
Pour le compilateur, cela signifie qu'il n'est pas nécessaire d'insérer une instruction membre .
Par conséquent, l'accès aux données n'a pas besoin d'arrêter les cœurs et d'attendre que les données soient écrites entre les caches globaux et locaux. C'est un avantage du fait que la mémoire n'est pas mutée .
Remarquez l' explication quelque peu simplificatrice ci-dessus qui supprime certains effets négatifs plus complexes de la mutabilité des données, par exemple sur le traitement en pipeline . Afin de garantir les commandes requises, le processeur doit invalider les pilotes affectés par les modifications de données, ce qui constitue un autre inconvénient en termes de performances. Si cela est mis en œuvre par une invalidation simple (et donc fiable :) de tous les pipelines, l’effet négatif est encore amplifié.