Outils pour utilisateurs

Outils du site


cours:informatique:dev:golang:demarrer_avec_go:120_concurrence

Notes et transcriptions du coursDémarrer avec Go” proposée par University of California, Irvine disponible sur la plateforme coursera.

Concurrence

L'un des grands avantages de Go est son implémentation de la concurrence. Nous allons donc parler un peu de ce qu'est la concurrence, de son utilité, de la façon dont Go l'implémente, de la présence de structures intégrées dans le langage qui facilitent l'utilisation de la concurrence.

Limites de performance

Je vais donc commencer par parler des limites de performance des ordinateurs. Cela s'explique par le fait que la motivation en faveur de la concurrence provient en grande partie du besoin de rapidité. C'est une grande partie de la motivation, pas la totalité, mais une grande partie. C'est pourquoi je vais présenter ces limites de performance sur les machines et expliquer comment la simultanéité peut vous aider à les contourner.

La loi de Moore, dit essentiellement que le nombre de transistors sur une puce double tous les 18 mois. C'était le cas par le passé, mais ce n'est plus le cas depuis peu. Grâce à ce doublement du nombre de transistors, les machines ont simplement accéléré. Parce qu'à mesure que les transistors devenaient un peu plus petits et qu'ils se rapprochaient les uns des autres, vous pouviez augmenter la fréquence d'horloge et donc les fréquences d'horloge ne cessaient d'augmenter. Je me souviens que lorsque j'étais à l'école, il y a quelque temps, on achetait une machine et en quelques mois seulement une autre bien plus puissance était disponible au même prix, ce qui pouvait être frustrant!

Donc, ces fréquences d'horloge ne faisaient qu' augmenter parce que le nombre de transistors ne faisait qu'augmenter. Les concepteurs de logiciels et les programmeurs devenaient paresseux. Ils écrivaient du code qui n'avait pas besoin d'être particulièrement efficace en termes de mémoire ou de vitesse, car ils savaient que très bientôt les techniciens doubleraient le nombre de transistors et régleraient tous leurs problèmes à leur place.

C'était une dérive mais c'est moins vrai maintenant car la loi de Moore a dû ralentir. Il y a plusieurs raisons pour lesquelles la plus importante serait probablement la consommation d'énergie et donc les contraintes de température.

Ainsi, lorsque vous rassemblez ces transistors sur une puce, ils génèrent de la chaleur. Chaque fois qu'ils changent d'état, ils consomment de l'énergie ce qui génère de la chaleur. Si vous continuez à augmenter la fréquence d'horloge, vous changez d'état à très haute fréquence, et cela finit par créer trop de chaleur qu'il devient difficile de dissiper et la puce fond physiquement.

Donc, si vous avez déjà ouvert une machine, vous voyez généralement un gros dissipateur thermique, un groupe ventilateur-radiateur qui est attaché au processeur. Ainsi, l'air ambiant est soufflé sur le ventilateur et dissipe la chaleur pour que la puce ne fonde pas.

Nous atteignons pratiquement les limites du refroidissement par air. Le refroidissement par air ne peut éliminer qu'une quantité limitée de chaleur par unité de temps. Si le battement d'horloge des puces augmente encore avec cette densité de transistors, elles risquent de fondre.

Vous ne pouvez donc pas continuer à augmenter les fréquences d'horloge. C'est donc la limite de performance qu'atteignent les machines, les fréquences d'horloge n'augmentent plus aussi vite qu'elles le faisaient auparavant.

Le parallélisme

Alors, comment améliorer les performances si vous ne pouvez pas simplement augmenter la fréquence ? Une façon de le faire est d'utiliser le parallélisme. Cela est généralement mis en œuvre de plusieurs manières, mais vous le constatez avec le nombre croissant de cœurs sur les puces.

A ce jour nous avons couramment des machines à quatre cœurs. Il y a quatre copies du noyau sur la puce. Un GPU, peut contenir 1 000 cœurs de processeur tous dans une matrice interne massive.

Le nombre de cœurs du processeur, augmente avec le temps, ce qui vous aide car vous pouvez potentiellement effectuer plusieurs tâches en même temps, pas toujours mais parfois. Si vous avez quatre cœurs, vous pouvez faire quatre choses à la fois. Cela peut améliorer votre vitesse, vous pouvez faire avancer les choses plus rapidement. Cependant cela n'améliorera pas nécessairement votre latence, mais votre débit pourrait s'améliorer.

Difficultés des traitements concurrents

Les difficultés liées à la mise en œuvre du parallélisme sont nombreuses. Du seul point de vue de la programmation, il y a des difficultés. Ainsi, par exemple, quand les tâches ont-elles commencé et quand s'arrêtent-elles ? C'est un programmeur qui doit en décider/coordonner. Les tâches ne sont pas totalement indépendantes alors, que se passe-t-il lorsqu'une tâche doit obtenir des données générées par une autre tâche ? Comment s'effectue ce transfert de données ? De plus, si plusieurs tâches s'exécutent en même temps, comment éviteront elles le conflit de mémoire ? Vous ne voulez pas qu'une tâche écrive dans sa variable A et que celle-ci remplace la variable B dans une autre tâche.

Ce sont donc des problèmes qui se produisent lorsque vous avez des exécutions concurrentes. Parce que même si vous avez plusieurs cœurs, vous devez vous soucier des accès à la mémoire. Doit on partager ou utiliser des espaces mémoire séparés ? Ce sont toutes des fonctionnalités du matériel, mais le programmeur doit souvent être conscient de ces choses et c'est difficile. Écrire du code qui peut s'exécuter en parallèle peut être difficile.

Programmation concurrente

La concurrence est la gestion de plusieurs tâches en même temps. Quand on dit en même temps, il se peut qu'elles ne s'exécutent pas nécessairement en même temps. Peut-être qu'elles s'exécutent sur un processeur monocœur. Elles ne s'exécutent donc pas en même temps, mais sont actives/présentes en même temps. Elles pourraient s'exécuter en même temps si vous en aviez les ressources, mais elles doivent fonctionner en même temps. L'une d’entre elles peut être suspendue pendant que les autres s'exécutent, mais elles sont toutes présentes en même temps et doivent être gérés au moins du point de vue de l'utilisateur en même temps.

C'est donc essentiel pour les grands systèmes. Il existe de grands systèmes qui comportent beaucoup de choses, de nombreuses processus et ils ne s'exécutent pas tous de manière séquentielle.

Vous voulez qu'ils soient capables de considérer 20 choses à la fois. peut-être qu'ils ne s'exécutent pas réellement en même temps, mais vous aimeriez avoir la possibilité de les exécuter en parallèle si possible, juste pour des raisons de rapidité.

Ainsi, la programmation concurrente permet le parallélisme. Si vous pouvez écrire du code de manière à ce que toutes ces tâches existent, que plusieurs tâches puissent être actives et communiquer en même temps, alors si vous avez les ressources (plusieurs cœurs, plusieurs éléments de mémoire), vous pouvez affecter les tâches à ces ressources parallèles et obtenir le parallélisme.

Vous ne pouvez pas simplement prendre un morceau de code normal et dire d'accord, je vais l'exécuter sur cinq cœurs, cela ne fonctionnera pas. Le programmeur doit décider comment partitionner ce code. Je veux que cela fonctionne sur un cœur, cela sur un autre, je veux ces données ici, ces données là et ainsi de suite. C'est donc le but de la programmation concurrente.

Le programme prendra alors les décisions qui permettent aux choses de fonctionner en parallèle si le matériel le permet.

Un programme concurrent inclut plusieurs éléments, une couche de dédiée ou plutôt une spécialisation :

  • La gestion de l'exécution des tâches. Ainsi, lorsque notre test démarre et s'arrête ;
  • La communication entre tâches : comment communiquent-elles, envoient-elles des données, partagent-elles de la mémoire ;
  • La synchronisation : Il arrive qu'une tâche doive faire quelque chose pour que la tâche suivante puisse commencer. Il se peut donc que deux tâches ne puissent pas être exécutées complètement en parallèle. Elles adoptent alors un comportement séquentiel. Ce test ne peut pas démarrer tant que cette tâche n'est pas terminée, etc.

C'est donc de la synchronisation et vous devez être capable de la gérer dans votre langage de programmation. La programmation doit essentiellement indiquer, dans le code, où la synchronisation doit avoir lieu et où elle ne doit pas avoir lieu.

C'est donc ce qu'est la programmation concurrente et c'est important si vous voulez pouvoir exploiter le parallélisme lorsqu'il est disponible matériellement.

Programmation concurrente en Go

Go possède de nombreuses primitives de mise en œuvre de la programmation concurrente intégrées au langage et implémentées efficacement.

  • Les Goroutines pour représenter une tâche concurrente, en gros un thread.
  • Les Channels sont utilisés pour la communication entre des tâches concurrentes.
  • Select est utilisée pour activer la synchronisation.

Ce ne sont que les mots clés de base à haut niveau que vous pouvez utiliser, nous en reparlerons plus loin dans le cours dédié à la programmation concurrente.

L'intégration de la concurrence dans le langage avec une implémentation efficace sont des avantages indéniables de nos jours. Les systèmes deviennent multi-cœurs et la programmation concurrente permet de les exploiter correctement.

◁ Précédent | ⌂ Retour au sommaire | Suivant ▷

cours/informatique/dev/golang/demarrer_avec_go/120_concurrence.txt · Dernière modification : 2024/05/03 10:10 de yoann