1 Parallélisme
Eric Goubault
Commissariat à l'Energie Atomique
Saclay
2 Pourquoi le parallélisme?
Le parallélisme, d'exotique il y a encore peu, est devenu indispensable:
- Les microprocesseurs, les machines ne sont presque plus ``séquentielles''
- Les systèmes d'exploitation (UNIX...) font tourner en permanence
des dizaines de tâches au moins
- Pour des raisons d'efficacité de calcul en temps et en mémoire,
de plus en plus
de programmes sont parallélisés (historiquement, chez les numériciens)
- Certains problèmes sont intrinsèquement parallèles ou distribués
(grandes bases de données: transactions simultanées! etc.)
3 Au niveau d'un microprocesseur (Athlon)...
4 Au niveau d'une machine...
5 Au niveau d'un réseau de machines...
6 Une des machines les plus puissantes au monde
(IBM ASCI White, Lawrence Livermore National Laboratory, 2000, 8192 processeurs
Power3 à 375Mhz: 12.3 teraflops! - simulation des armes thermonucléaires)
7 Mais subtil à programmer...
- Nouvelles primitives (® programmation)
- Nouveaux types de bugs, dans la coordination des tâches (® sémantique
mathématique); exemple académique (trois
philosophes qui dînent):
- Difficulté d'atteindre les performances crêtes (® algorithmique)
8 Programme
- Les ``threads'' en JAVA (rappel, et simulation modèles PRAM etc.)
- Les ``nouveaux'' problèmes liés au parallélisme (problème de coordination, exclusion mutuelle, points morts etc.)
- L'algorithmique parallèle de base (PRAM, complexité, réseaux de tri, algorithmes sur anneau etc.)
- L'ordonnancement de tâches
- Au delà du multitâche (``clusters'' de stations, distribution, RMI, JavaParty etc.)
9 Organisation
- Complémentaire du cours système, faisant suite au cours d'informatique fondamentale (avec
quelques rappels)
- Cours suivis de TPs et de TDs (utilisation des threads JAVA)
- Ecrit
- Voir par exemple le cours de l'année dernière:
http://www.enseignement.polytechnique.fr/profs/informatique/
Eric.Goubault/ParaI.html
et http://www.enseignement.polytechnique.fr/profs/informatique/
Eric.Goubault/pvm.html
10 Plan de ce cours en particulier
- Introduction
- Modèles du parallélisme, une première approche
- Threads JAVA (rappels)
11 Introduction
Machine parallèle =
ensemble de processeurs qui coopèrent
et communiquent
Historiquement, réseaux d'ordinateurs, machines
vectorielles et faiblement parallèles (années 70 - IBM 360-90 vectoriel, IRIS 80 triprocesseurs, CRAY 1 vectoriel...)
12 Taxonomie de Tanenbaum:
Quatre types: SISD, SIMD, MISD et MIMD.
Basée sur les notions de flot de contrôle et flot de
données.
13 Taxonomie de Tanenbaum (1):
Machine SISD |
= |
Single Instruction Single
Data |
|
= |
Machine Von Neuman
|
14 Exemple
Le code suivant,
int A[100];
...
for (i=1;100>i;i++)
A[i]=A[i]+A[i+1];
s'exécute sur une machine séquentielle en faisant les additions
A[1]+A[2], A[2]+A[3], etc., A[99]+A[100] à la suite les unes des
autres.
15 Taxonomie de Tanenbaum (2):
Machine SIMD = Single Instruction Multiple
Data
- (1) Parallèle (Connection Machine)
- (2) Systolique
En général exécution synchrone
16 Exemple
En CM-Fortran sur la Connection Machine-5 avec 32 processeurs,
INTEGER I,A(32,1000)
CMF$ LAYOUT A(:NEWS,:SERIAL)
...
FORALL (I=1:32,J=1:1000)
$ A(I:I,J:J)=A(I:I,J:J)+A(I:I,(J+1):(J+1))
Chaque processeur i, 1 £ i £ 32
a en sa mémoire locale une tranche du tableau
A: A(i,1), A(i,2), ..., A(i,1000). Il n'y a pas d'interférence
dans le calcul de la boucle entre les différentes tranches: tous les
processeurs exécutent la même boucle sur sa propre tranche en même
temps.
17 Exemple
18 Taxonomie de Tanenbaum (3):
Machine MISD = Multiple Instruction Single
Data
Processeurs vectoriels, architectures pipelines
19 Exemple
Pipelinage d'une addition vectorielle,
FOR i:=1 to n DO
R(a+b*i):=A(a'+b'*i)+B(a''+b''*i);
A, B et R sont placés dans des registres vectoriels
qui se remplissent au fur et à mesure du calcul,
20 Exemple
Temps |
A |
( |
i |
) |
B |
( |
i |
) |
R |
( |
i |
) |
1 |
1 |
. |
. |
. |
1 |
. |
. |
. |
. |
. |
. |
. |
2 |
2 |
1 |
. |
. |
2 |
1 |
. |
. |
. |
. |
. |
. |
3 |
3 |
2 |
1 |
. |
3 |
2 |
1 |
. |
. |
. |
. |
. |
4 |
4 |
3 |
2 |
1 |
4 |
3 |
2 |
1 |
. |
. |
. |
. |
5 |
5 |
4 |
3 |
2 |
5 |
4 |
3 |
2 |
1 |
. |
. |
. |
6 |
6 |
5 |
4 |
3 |
6 |
5 |
4 |
3 |
2 |
1 |
. |
. |
etc. |
|
|
|
|
|
|
|
|
|
|
|
|
21 Taxonomie de Tanenbaum (4):
Machine MIMD = Multiple Instruction Multiple
Data
- (1) Mémoire partagée (Sequent)
- (2) Mémoire locale + réseau de communication (Transputer, Connection
Machine, local, par réseau d'interconnexion) - Système réparti
C'est le cas (2) que l'on va voir plus particulièrement avec RMI. On
pourra également simuler le cas (1) (que l'on verra plus avec les
threads JAVA).
22 Mémoire Partagée
23 Mémoire Partagée
Synchronisation par,
- Barrières de synchronisation,
- Sémaphores : deux opérations P et V.
- Verrou (mutex lock) : sémaphore binaire qui sert à
protéger une section critique.
- Moniteurs : construction de haut niveau, verrou implicite.
24 Machine distribuée
25 Machine distribuée
Synchronisation et échange d'information par,
- Appel de procédure distribuée (RPC ou RMI en ce qui nous concernera) :
- réponse synchrone
- réponse asynchrone
- Envoi/Réception de message asynchrone (tampon de taille limitée ou non); active
polling ou gestion à l'arrivée par une procédure handler.
- Envoi/Réception de message synchrone : rendez-vous.
- Mélange des deux derniers cas.
26 Exemple -- Clients/Serveurs
Le protocole RPC (``Remote Procedure Call'') entre machines UNIX avec
réseau Ethernet est un exemple de programmation MIMD:
27 Remarques
Architectures plus ou moins adaptées à certains problèmes.
Gain de temps espéré: au plus N (nombre de processeurs).
En pratique, parallélisme difficile à contrôler
28 Programmation parallèle:
- (1) Language séquentiel: le compilateur parallélise
(Fortran...), voir fin du poly d'Y. Robert
- (2) Constructions parallèles explicites (Parallel C, Occam...)
29 Constructions parallèles explicites
- Création de parallélisme,
- Itération simultanée sur tous les processeurs
(FOR parallèle de Fortran),
- Définition d'un ensemble de processus (COBEGIN),
- Création de processus (FORK de Unix)
- Contrôle du parallélisme,
- Synchronisation (Rendez-vous d'Ada),
- Passage de messages (synchrones/asynchrones,
broadcast,...),
- Section critiques (gestion de la mémoire partagée),
- Stopper une exécution parallèle (COEND, WAIT
d'Unix)
30 Processus (MIMD)
Un Processus est une unité de programme séquentielle
(abstraction d'un processeur)
avec,
- sa propre pile de données,
- son compteur ordinal,
- éventuellement sa mémoire locale
31 Constructions parallèles explicites (suite):
32 Constructions parallèles explicites (suite):
Synchronisation: but = assurer qu'à un moment donné tous
les processus ont suffisament avancés leurs calculs.
Erreurs possibles: Interblocage (deadlock, livelock),
Famine,... (cours 2 et 3)
Exemples:
- X dit à Y: ``Donne moi ton nom et je te dirai le mien''.
Y dit la même chose à X. Ceci est une situation d'interblocage.
- X et Y veulent tous deux utiliser un objet. X est plus rapide
qu'Y et obtient régulièrement l'utilisation de cet objet avant Y qui
ne l'obtient jamais.
On dit que Y est en situation de famine.
33 Constructions parallèles explicites (suite):
MIMD mémoire partagée,
Erreurs possibles: incohérence des
données.
Partant de x=0, on exécute x:=x+x en parallèle avec x:=1. Par exemple, on a ces trois exécutions possibles:
LOAD x,R1 |
WRITE x,1 |
LOAD x,R1 |
LOAD x,R2 |
LOAD x,R1 |
WRITE x,1 |
WRITE x,1 |
LOAD x,R2 |
LOAD x,R2 |
WRITE x,R1+R2 |
WRITE x,R1+R2 |
WRITE x,R1+R2 |
Résultat x=0 |
Résultat x=2 |
Résultat x=1
|
Pour y remédier, sections critiques et exclusion mutuelle.
34 Réseaux de stations
Pas d'horloge globale, mode MIMD, communication par passage de messages
(typiquement gérés par PVM, MPI dans le monde numérique, voir,
- http://www-unix.mcs.anl.gov/mpi/
- http://www.csm.ornl.gov/pvm/pvm_home.html
)
sur un réseau local ou d'interconnexion.
35 Architectures hybrides
Combinaison sur un réseau local de stations et de machines multiprocesseurs
(elles-même gérant leur parallélisme interne par mémoire partagée
ou par bus ou réseau).
Par exemple threads JAVA+RMI.
36 Threads JAVA
- Concept répandu mais annexe dans d'autres langages de programmation (C ou
C++ par exemple),
- Concept intégré dans JAVA (mais aussi ADA)
- Thread = ``Thread of Control'', processus léger etc.
- un Thread est un programme séquentiel, avec sa propre mémoire locale,
s'exécutant en même temps, et sur la même machine virtuelle JAVA, que d'autres
threads
- communication à travers une mémoire partagée (ainsi que des méthodes
de synchronisations)
37 Utilité des threads
- Plus grande facilité d'écriture de certains programmes (extension de la
notion de fonction)
- Systèmes d'exploitation
- Interfaces graphiques
- Ordinateurs multi-processeurs (bi-pentium etc.)
38 Création
Pour créer un thread, on crée une instance de la classe Thread,
Thread Proc = new Thread();
- on peut configurer Proc, par exemple lui associer
une priorité,
- on peut l'exécuter
en invoquant la méthode start du thread,
39 Exécution
- start() va
à son tour invoquer la méthode run du thread (qui ne fait rien par défaut)
- C'est possible par exemple si on définit Proc comme une
instance d'une sous-classe de Thread, dans laquelle on redéfinit
la méthode run.
- Les variables locales sont des champs de cette sous-classe.
40 Exemple
class Compte extends Thread {
int valeur;
Compte(int val) {
valeur = val;
}
public void run() {
try {
41
for (;;) {
System.out.print(valeur + " ");
sleep(100);
}
} catch (InterruptedException e) {
return;
}
}
public static void main(String[] args) {
new Compte(1).start();
new Compte(2000).start();
}
}
42 Exécution
L'exécution du programme main donne quelque chose comme,
> java Compte
1 2000 2000 1 1 1 1
^C
>
43 Remarques
- Les entiers valeur sont distincts dans les deux threads qui
s'exécutent. C'est une variable locale au thread.
- Si on avait déclaré static int valeur, cette variable
aurait été partagée par ces deux threads (durée de vie=celle des
threads).
- Si on avait déclaré Integer valeur (``classe enveloppante''
de int), cette classe aurait été partagée par tous les
threads et aurait une durée de vie éventuellement supérieure à celle
des threads
44 Arrêt
- méthode stop() (dangereux et n'existe plus en JAVA 2),
- méthode sleep(long) (suspension du thread pendant un certain
nombre de nanosecondes)
45 Mais...
- Pas d'héritage multiple en JAVA, donc on ne peut pas hériter de Thread et d'une autre classe en même temps,
- Il est alors préférable d'utiliser l'interface Runnable.
46 L'interface Runnable
- L'interface Runnable représente du code exécutable,
- Elle ne possède
qu'une méthode, public void run();
- Par exemple la classe Thread implémente l'interface
Runnable.
- Mieux encore, on peut construire une instance
de Thread à partir d'un objet qui implémente l'interface
Runnable par le constructeur:
public Thread(Runnable target);
47 Exemple
class Compte implements Runnable {
int valeur;
Compte(int val) {
valeur = val;
}
public void run() {
try {
for (;;) {
System.out.print(valeur + " ");
sleep(100);
}
48 Exemple
} catch (InterruptedException e) {
return;
}
}
public static void main(String[] args) {
Runnable compte1 = new Compte(1);
Runnable compte2 = new Compte(2000);
new Thread(compte1).start();
new Thread(compte2).start();
}
}
49 Déterminer la terminaison d'un thread
- isAlive() renvoie un booléen indiquant si un thread est encore
vivant (après que start() se soit exécuté, et avant la fin normale ou
imposée par stop()),
50 Déterminer la terminaison d'un thread
51 Nommer les threads
- void setName(String name) nomme un thread: utile essentiellement
pour le debugging (toString() renvoie ce nom)
- String getName() renvoie le nom du thread.
52 Informations sur les threads
- static Thread currentThread() renvoie la référence au Thread courant
c'est-à-dire celui qui exécute currentThread(),
- static int enumerate(Thread[] threadArray) place tous les threads existant
(y compris le main() mais pas le thread ramasse-miettes) dans le tableau threadArray et renvoie leur nombre.
- static int activeCount() renvoie le nombre de threads.
53 Exemple
class Compte3 extends Thread {
int valeur;
Compte3(int val) {
valeur = val;
}
public void run() {
try {
for (;;) {
System.out.print(valeur + " ");
sleep(100);
}
54
} catch (InterruptedException e) {
return; } }
public static void printThreads() {
Thread[] ta = new Thread[Thread.activeCount()];
int n = Thread.enumerate(ta);
for (int i=0; i<n; i++) {
System.out.println("Le thread "+ i + " est
" + ta[i].getName());
} }
public static void main(String[] args) {
new Compte3(1).start();
new Compte3(2000).start();
printThreads(); } }
55 Exécution
% java Compte3
1 2000 Le thread 0 est main
Le thread 1 est Thread-2
Le thread 2 est Thread-3
1 2000 1 2000 1 2000 1 2000 2000
1 1 2000 2000 1 1 2000 2000 1 1
2000 2000 1 1 2000 2000 1 1 2000
2000 1 1 2000 2000 1 1 ^C
%
This document was translated from LATEX by HEVEA.