alt.net modéliser parallèle avec c# 4.0
Post on 21-Jun-2015
1.171 Views
Preview:
DESCRIPTION
TRANSCRIPT
Modéliser Parallèle avec C# 4.0
21 avril 2010Bruno BOUCARDboucard.bruno@free.fr
http://blogs.msdn.com/devpara/default.aspxhttp://msmvps.com/blogs/brunoboucard
Code Session : TCP301
Méthode itérative
Choisir une stratégie et un
algorithme adaptés
Implémenter son algorithme avec un
pattern qui le supporte
Trouver la concurrence
Mesurer les performances de la
solution
Etape 1
Mesurer les performances de la solution
Etape 1Analyser les performances
• Analyser les coûts de la solution séquentielle
Analyser les performances
Démonstration
Etape 2
Trouver la concurrence
• Terminer avec une décomposition de tâches ordonnées en fonction des dépendances techniques et fonctionnelles, compléter par les données partagées que vous aurez identifiées
• Il arrive qu’on passe d’une décomposition orientée tâches à une décomposition orientée données ou bien flux de données en fonction du type de traitement
Etape 2Trouver la concurrence
• Commencer avec un cahier des charges qui décrit le problème• Quel que soit le contexte fonctionnel ou technique, vous serez guidé
naturellement par l’une des décompositions
Evaluer le design
Grouper les tâches
Ordonner les tâches
Analyse des dépendances
Partager les données
Commencer
Analyser les dépendances- Visual Studio 2010 : Architecture -> Generate Dependency Graph- NDepend: http://www.ndepend.com/
Orientée tâches
Orientée données
Décomposition
Trouver la concurrence
Démonstration
Trouver la concurrenceSolution séquentielle
Sélectionner un
répertoire
Charger tous les noms d’images
dans le répertoire et ses sous répertoires
Twister l’image
Normaliser l’image
Convertir l’image en
une vignette
Charger une image
Dépiler un nom
de fichier
Empiler les noms de fichiers
sélectionnés
Insérer dans le contrôle graphique
WM_TIMER
Structure de pile partagée
Etape 2Décomposition et granularité
• Votre décomposition en tâches doit tenir compte de leur granularité et de leur surcoût
tâche
tâche
tâche
tâche
Cœur 1
tâche
tâche
tâche
tâche
Cœur 2
tâche
tâche
tâche
tâche
Cœur 0
tâche
tâche
tâche
tâche
Cœur 3
Configuration 1
Cœur 0
tâche
Cœur 1
tâche
Cœur 2
tâche
Cœur 3
tâche
Configuration 2
Quelle est la meilleure configuration ?surcoût
charge
Etape 2Décomposition et répartition de charge
• Votre groupement de tâches doit tenir compte de leur charge
tâche
tâche
tâche
tâche
Cœur 1
tâche
tâche
Cœur 2
tâche
Cœur 0
tâche
Cœur 3
Configuration 1
tâche
tâche
Cœur 1
tâche
tâche
Cœur 2
tâche
Cœur 0
tâche
Cœur 3
tâche
tâche
Configuration 2
Quelle est la meilleure configuration ?surcoût
charge
Etape 2Evaluer votre design• Flexibilité
– Préférer l’abstraction pour faciliter l’adaptation à différents scénarios d’exécution
• Nombre de cœurs sollicités• Partitionnement des données
• Efficacité– Le temps dépensé à gérer le parallélisme vs le temps gagné à tirer
parti des cœurs– Amélioration des performances en fonction du nombre de
processeurs• Simplicité
– Le code peut être facilement diagnostiqué– La solution technique choisie est facile à maintenir
Etape 3
Choisir un algorithme en
fonction de votre stratégie
Etape 3Choisir un algorithme en fonction de votre stratégie
Décomposition orientée
Données
Linéaires ?
Décomposition géométrique
Récursives ?
Décomposition récursive
Tâches
Linéaires ?
Parallélisme de tâches
Récursives ?
Diviser pour régner
Flux de données
Régulier ?
Pipeline
Irrégulier ?
Coordination orientée
événements
Etape 3Algorithmes données• Décomposition géométrique
Traitement d’une collection d’images, addition de matrices …
Taille des morceaux • Trop grand – sous utilisation• Trop petit – sur consommation
Format des morceaux• Attention au false sharing
• Éviter l'allocation de mémoire contiguë• Deux champs d'instance dans la même instance de classe sont proches dans
leurs emplacement de mémoire • Deux champs statiques dans le même type sont proches en mémoire• Deux éléments avec des index adjacents dans un tableau sont proches en
mémoire • Les objets alloués consécutivement sont probablement proches en mémoire• Les variables locales utilisées ensemble dans une fermeture sont
probablement capturées dans les champs d'instance, et ainsi, d'après le premier commentaire ci-dessus, sont également proches en mémoire
ModéliserAlgorithmes données – Attention au False Sharing
• Pour des raisons de performances, les systèmes utilisent des lignes de cache
• Lorsque des threads sur différents processeurs modifient en parallèle les variables qui résident sur la même ligne de cache, le False Sharing n’est pas loin
Cache
Ligne de cache
Mémoire
Coeur 0 Coeur 1T0 T1
Cache
Ligne de cache
Algorithmes données: False Sharing
Démonstration
Etape 3Décomposition géométrique
for (int i = 0; i < size; i++) { Parallel.For(0, size, j => { int temp = 0; for (int k = 0; k < size; k++) { temp += m1[i, k] + m2[k, j]; } result[i, j] = temp; });}
Etape 3Algorithmes données
Décomposition récursive
Parcours de graphe ou parcours d’arbre …
2 tâches
3 tâches
3 tâches
1 tâche
Le choix de la profondeur détermine la performance- Arbre profond • contention processeurs- Arbre de profondeur limitée• sous utilisation des processeurs
Etape 3Récursivité sur des données
static void Walk<T>(Tree<T> root, Action<T> Action){ if (root == null) return; var t1 = Task.Factory.StartNew(() => action(root.Data)); var t2 = Task.Factory.StartNew(() => Walk(root.Left, action)); var t3 = Task.Factory.StartNew(() => Walk(root.Rigth, action)); Task.WaitAll(t1, t2, t3);}
Etape 3Algorithmes tâches• Parallélisme de tâches linéaires
Paralléliser des opérations décomposables
sous opération 4sous opération 1sous opération 2
sous opération 3
sous opération 1
sous opération 2
sous opération 3
sous opération 4
Nombre de tâches• trop peu: les cœurs sont sous utilisés• trop élevé: contention des tâchesDépendances• retirables• séparables• lecture seule ou lecture/écriture
Etape 3Algorithmes tâches
Diviser pour régner
QuickSort
Résoudre
Problème
Sous - problème Sous - problème
Sous - problème Sous - problème Sous - problème Sous - problème
Sous - problème Sous - problème Sous - problème Sous - problème
Sous - solutionSous - solution
Solution
Split
SplitSplit
RésoudreRésoudreRésoudre
Fusionner Fusionner
Fusionner
Séquentiel
2 chemins parallèles
4 chemins parallèles
2 chemins parallèles
Séquentiel
Arbres profond • contention processeursArbres de profondeur limitée• sous utilisation des processeur
Etape 3Diviser pour régner
static void QuickSort<T>(T[] data, int fromInclusive, int toExclusive) where T : IComparable<T>{ if (toExclusive - fromInclusive <= THRESHOLD) { InsertionSort(data, fromInclusive, toExclusive); } else { int pivotPos = Partition(data, fromInclusive, toExclusive); if (toExclusive - fromInclusive <= PARALLEL_THRESHOLD) { // NOTE: PARALLEL_THRESHOLD is chosen to be greater than THRESHOLD. QuickSort(data, fromInclusive, pivotPos); QuickSort(data, pivotPos, toExclusive); } else Parallel.Invoke( () => QuickSort(data, fromInclusive, pivotPos), () => QuickSort(data, pivotPos, toExclusive)); }}
Etape 3Algorithmes flux de données• Pipeline
Chaîne de montage automobile
Les charges de travail des étapes• égales – pipeline linéaire• inégales – pipeline non-linéaire
Etape 3Algorithmes flux de données
Coordination orientée événements
Traitement d’une dépêche sur un desk journalistique …
Etape 3Pipeline
var input = new BlockingCollection<string>(); var readLines = Task.Factory.StartNew(() => { try { foreach(var line in File.ReadAllLines(@"input.txt")) input.Add(line); } finally { input.CompleteAdding(); } }); var writeLines = Task.Factory.StartNew(() => { File.WriteAllLines(@"output.txt", input.GetConsumingEnumerable()); }); Task.WaitAll(readLines, writeLines);
Etape 4
Choisir un pattern de structure
Etape 4Choisir un pattern de structures de programme
• Après avoir sélectionné votre algorithme parallèle, il faut maintenant le supporter dans votre programme
Master/Worker
Structures de programme
Boucle parallèle
Fork/Join
SPMD
Etape 4Les Patterns de structures de programme• SPMD, Master/Worker, Boucle parallèle et Fork/Join
partagent les mêmes idiomes
Partitionner
Exécuter Fusionner
Etape 4Fork / Join
var tasks = new Task[3];tasks[0] = new Task(() => ComputeMean());tasks[1] = new Task(() => ComputeMedian());tasks[2] = new Task(() => ComputeMode());foreach(Task t in tasks) t.Start(); Task.WaitAll(tasks);
Parallel.Invoke(() => ComputeMean(),() => ComputeMedian(),() => ComputeMode()
);
Etape 4Boucle parallèle
Parallel.ForEach(stack, bitmap =>
_imagesStack.Push(ProcessBitmap(bitmap)));
var query = from bitmap in stack.AsParallel() select ProcessBitmap(bitmap);
query.ForAll(image => _imagesStack.Push(image));
Etape 4Structures de programme parallèle• Appliquées dans différents contextes
– SPMD – Systèmes distribués• MPI, SOA, Grid Computing,
– Fork / Join – Orienté Tâches• TPL
– Master/Worker – Orienté Tâches• TPL
– Boucle Parallèle – Orienté Données • TPL, PLINQ
Structures de programme parallèle
Démonstration
Structures de programme parallèle Solution parallèle
Sélectionner un
répertoire
Charger tous les noms d’images
dans le répertoire et ses sous répertoires
Dépiler une
vignette
Empiler les noms de fichiers
sélectionnés
Insérer dans le contrôle graphique
WM_TIMER
Pile partagée concurrente
Twister l’image
Normaliser l’image
Convertir l’image en
une vignette
Charger une image
Collection des noms de fichiers
Etape 1
Mesurer les performances de la solution
Etape 1Analyser les performances
• Analyser les coûts de la solution parallèle
Structures de programme parallèle
Démonstration
ConclusionQuelques suggestions pour l’implémentation
• Préférer les nouveaux outils de haut niveau d’abstraction
• Privilégier les solutions simples à maintenir– La granularité fine est souvent synonyme de
complexité
• Utiliser systématiquement des librairies thread-safe– Fiabilité == Gain de temps
• Ne jamais présumer d’un ordre d’exécution– La justesse du code est à ce prix
ConclusionPour retrouver le « Free Lunch »• Respecter les 4 grandes étapes
– Notamment les « analyses des dépendances » et « analyses des performances »
• Avancer de manière itérative– Difficile de trouver « la solution » du premier coup
• Si possible privilégier les capacités de monter en charge ainsi que la simplicité
• Mesurer régulièrement les performances de vos choix– Visual Studio 2010 est votre ami
• Si vos choix ne vous semblent pas satisfaisants– Oser changer votre algorithme pour augmenter ses chances de
parallélisation
• Penser Parallèle– C’est en pratiquant régulièrement la méthode présentée que vous
gagnerez en réflexes sur l’usage des Patterns parallèles les mieux adaptés à vos besoins
Vous n’êtes pas seul !Livres et blogues• Mes ouvrages préférés
–Programmation Parallèle• http://msmvps.com/blogs/brunoboucard
• Portail Microsoft Parallel Computing– http://msdn.microsoft.com/en-us/concurrency
• Patterns for Parallel Programming de Stephen Toub– http://www.microsoft.com/downloads/details.aspx?FamilyID=86b3d32b-ad26-4bb8-a3ae-
c1637026c3ee&displaylang=en
top related