Langage C# – Exécuter une requête LINQ de « manière parallèle »

LINQ For Object (Language INtegrated Query) est un langage intégré au langage C# permettant d’exécuter une requête sur une grappe d’objets. Paru en 2008, il a permis de révolutionner la manière dont les développeurs écrivaient leurs traitements algorithmiques, en ne faisant plus obligatoirement appel aux structures itératives (telles que for each …) et conditionnelles (telles que if …).

Voici un exemple dans lequel nous essayons de vérifier le format d’un million d’adresses email avec une expression régulière :

static void Main(string[] args)
{
    // Variables locales.
    List<string> listeEmails;
    int iNombreEMailsValides;
    Stopwatch oStopwatch;

    // Initialisation.
    listeEmails = File.ReadAllLines(@"Emails.txt").ToList();
    oStopwatch = new Stopwatch();

    oStopwatch.Start();

    iNombreEMailsValides = (from sEmail in listeEmails
                            where Regex.IsMatch(sEmail, @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")
                            select sEmail).Count();

    oStopwatch.Stop();

    Console.WriteLine($"{iNombreEMailsValides} emails valides trouvés en {oStopwatch.Elapsed.TotalSeconds.ToString("0.00")} secondes");

    Console.Read();
}

Sur mon PC, ce bloc de code permet de vérifier le format des 1 000 000 en 10,43 secondes.

Grâce à PLINQ (inclus dans le Framework .NET), nous pouvons paralléliser la vérification de cet ensemble d’adresses mails. Modifions la requête LINQ :

iNombreEMailsValides = (from sEmail in listeEmails.AsParallel()
                        where Regex.IsMatch(sEmail, @"\w+([-+.']\w+)*@\w+([.]\w+)*\.\w+([-.]\w+)*")
                        select sEmail).Count();

Sur mon PC, ce bloc de code permet de vérifier le format des 1 000 000 en 4,63 secondes. Ce résultat est intéressant car il montre un gain en temps d’exécution de 56%.

Faut-il utiliser PLINQ pour exécuter toutes les requêtes LINQ ? Dans certains cas, son utilisation peut avoir l’effet inverse : pénaliser les performances d’exécution d’une requête. Le temps passé à initialiser le moteur d’exécution parallèle et à créer de nouveaux threads pour exécuter la requête n’est pas compensé par le temps passé à la « parallélisation » de son exécution. Il n’est alors pas intéressant de paralléliser l’exécution de toutes les requêtes LINQ.

About: James RAVAILLE

Travaillant avec la plateforme Microsoft .NET depuis 2002, j’alterne les missions de formation et d’ingénierie avec cette plateforme. J’écris ce blog pour transmettre mes connaissances à tout développeur, qu’il soit débutant ou expérimenté.