Programmation parallèle en .NET

Un petit test de la parallélisation en .NET, avec la CTP de Juin 2008 des Parallel Extensions.

A utiliser, c’est très simple : on utilise une nouvelle librairie System.Threading, qui rajoute des opérateurs parallélisés ainsi que des listes supportant la parallélisation.

Voici un petit bout de code pour tester sur un AMD 64X2 4400+, avec donc deux coeurs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace TestParallelisation
{
 class Program
 {
  static void Main(string[] args)
  {
   List<int> Entiers = new List<int>();

   for (int ind = 100000; ind < 120000; ind++)
    Entiers.Add(ind); Stopwatch Chrono = Stopwatch.StartNew();
   List<int> Premiers = new List<int>();

   foreach (int Entier in Entiers)
    if (EstPremier(Entier))
     Premiers.Add(Entier);
   Console.WriteLine("{0} premiers trouvés en {1} ms", Premiers.Count, Chrono.Elapsed.Milliseconds);

  &nbsp;Chrono = Stopwatch.StartNew();
   List<int> PremiersSynchro = new List<int>();
   Parallel.ForEach<int>(Entiers, i => { if (EstPremier(i)) PremiersSynchro.Add(i); });
   Console.WriteLine("{0} premiers trouvés en {1} ms", PremiersSynchro.Count, Chrono.Elapsed.Milliseconds);
  }

  private static bool EstPremier(int Nombre)
  {
   for (int ind = 2; ind < Nombre - 1; ind++)
    if (Nombre % ind == 0)
     return false;
   return true;
  }
 }
}

On voit qu’on cherche la liste des nombres premiers entre 100 000 et 120 000, avec une première version standard, et qui s’exécutera donc sur un seul core, et une seconde permettant la parallélisation. Ici, rien de compliqué puisque chaque nombre est traité séparément, donc c’est très simple de répartir sur autant de processeurs que nécessaire.

Les résultats : 539 ms en mono-core, 388 ms en parallèle sur deux cores. Une amélioration de performance d’environ 30%, en informatique, c’est déjà pas mal… Et imaginez sur un octo-core. Les résultats varient un peu en fonction du temps, mais on a une bonne idée du ratio sur ce type d’algo.

Toutefois, un bug est présent dans ce code : on écrit les résultats dans une liste d’entiers, et le multithread peut faire que les résultats sont écrits en même temps, résultant en des écrasements, que j’ai pu constater sur un test avec un résultat de référence de 1709 entiers premiers, et 1708 seulement sur le deuxième.

Le premier réflexe est de créer plusieurs listes et de les grouper à la fin, mais comment faire quand on n’a pas la main sur le nombre de threads ? Après recherche sur internet, il se trouve que Microsoft a tout prévu. Au lieu d’utiliser des listes génériques, il faut utiliser System.Threading.BlockingCollection<T>, qui est faite spécialement pour ça…

Bref, un premier essai convaincant !

About JP Gouigoux

Jean-Philippe Gouigoux est Architecte Logiciel, MVP Connected Systems Developer. Il intervient régulièrement à l'Université de Bretagne Sud ainsi qu'à l'Agile Tour. Plus de détails sur la page "Curriculum Vitae" de ce blog.
This entry was posted in .NET, Parallélisation. Bookmark the permalink.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha Captcha Reload