Comment travailler avec Parallel LINQ en C #

Language Integrated Query, également connu sous le nom de LINQ, est un pipeline d'exécution de requête qui ajoute des capacités de requête aux langages ciblés sur l'environnement géré de .Net. Parallel LINQ, ou PLINQ, est un moteur d'exécution de requêtes qui s'exécute au-dessus de l'environnement géré de .Net et tire parti des multiples processeurs ou cœurs de votre système informatique pour exécuter les requêtes en parallèle. En d'autres termes, il vous permet d'optimiser vos requêtes en les fractionnant en parties afin d'exécuter ces parties en parallèle et ainsi d'augmenter les performances des requêtes.

PLINQ est une extension de LINQ et a été introduit dans le cadre de .Net Framework 4. Il s'agit d'un moteur d'exécution de requêtes de Microsoft et fait partie de la bibliothèque d'extensions parallèles. La bibliothèque d'extensions parallèles est à son tour composée de TPL (Task Parallel Library) et PLINQ. Microsoft a pris en charge la programmation parallèle dans .Net Framework pour tirer parti des avantages des systèmes multicœurs. Pour tirer parti des capacités de programmation parallèle, une nouvelle classe appelée Parallel a été introduite dans .Net Framework 4.

PLINQ est un bon choix dans les opérations liées au calcul. Mais, de quoi s'agit-il et quels sont les problèmes qu'il peut résoudre? Est-il approprié de l'utiliser à la place de LINQ chaque fois que nous avons besoin d'interroger des données? Nous discuterions de tout cela dans un instant, mais voyons d'abord comment PLINQ fonctionne dans les coulisses. PLINQ fonctionne en partitionnant la source de données ou l'entrée en morceaux qui à leur tour sont exécutés par différents threads.

Un peu de code maintenant

Considérez la requête LINQ suivante.

var data = from e in employees

           where e.FirstName.StartsWith("J")

           select e;

Vous pouvez facilement convertir la requête ci-dessus en requête PLINQ à l'aide de la méthode d'extension AsParallel. Notez qu'AsParallel est une méthode d'extension de la classe System.Linq.ParallelEnumerable.

var data = from e in employees.AsParallel()

           where e.FirstName.StartsWith("J")

           select e;

Si vous souhaitez conserver l'ordre du résultat de la requête, vous pouvez tirer parti de la méthode AsOrdered.

var data = from e in employees.AsParallel().AsOrdered()

           where e.FirstName.StartsWith("J")

           select e;

Vous pouvez également conserver l'ordre des données renvoyées à la suite de l'exécution de la requête PLINQ en transmettant QueryOptions.PreserveOrdering en tant que paramètre à la méthode AsParallel.

var data = from e in employees.AsParallel(QueryOptions.PreserveOrdering)

           where e.FirstName.StartsWith("J")

           select e;

Notez que l'utilisation de la méthode AsParallel () n'est pas recommandée sur les petites collections - elle s'exécuterait plutôt plus lentement qu'une requête normale. Et si vous voulez forcer le parallélisme? Ce n'est cependant pas recommandé, mais vous pouvez utiliser la méthode d'extension WithExecutionMode pour y parvenir. Voici un exemple qui illustre cela.

var data = from e in employees.AsParallel().WithExecutionMode

                (ParallelExecutionMode.ForceParallelism)

           where e.FirstName.StartsWith("J")

           select e;

Notez que ParallelExecutionMode est une énumération qui est disponible dans le cadre de l'espace de noms System.Linq et peut avoir l'une de ces valeurs: Default et ForceParallelism. Si vous spécifiez Default comme paramètre de la méthode d'extension WithExecutionMode, PLINQ exécutera la requête en parallèle si une amélioration des performances est évidente lors de l'exécution de la requête en parallèle. Sinon, PLINQ exécutera la requête comme une requête LINQ. Au contraire, si vous spécifiez ForeParallelism en tant que paramètre de la méthode d'extension WithExecutionMode, PLINQ exécutera la requête en parallèle même si cela pourrait entraîner une baisse des performances.

Comment limiter le degré de parallélisme?

Vous devez également être conscient d'un autre concept connexe: le degré de parallélisme. Il s'agit d'un nombre entier non signé qui indique le nombre maximal de processeurs dont votre requête PLINQ doit tirer parti pendant son exécution. En d'autres termes, le degré de parallélisme est un entier qui indique le nombre maximal de tâches qui seraient exécutées simultanément pour traiter une requête.

Incidemment, la valeur par défaut du degré de parallélisme est 64, ce qui implique que PLINQ peut exploiter un maximum de 64 processeurs dans votre système. Voici comment vous pouvez limiter le degré de parallélisme dans PLINQ à deux processeurs dans votre système.

var data = from e in employees.AsParallel().WithDegreeOfParallelism(2)

           where e.FirstName.StartsWith("J")

           select e;

Notez comment le nombre de processeurs a été passé en argument à la méthode WithDegreeofParallelism. Vous devez spécifier une valeur plus élevée pour le degré de parallélisme pour les gains de performances si votre requête effectue plus de travail non lié au calcul, c'est-à-dire non lié au processeur.

Je recommande vivement la lecture du document "Patterns of Parallel Programming" de Stephen Toub. Il fournit une discussion approfondie sur les modèles de programmation parallèle dans .Net.