Conservation de l'ordre en PLINQOrder Preservation in PLINQ

Dans PLINQ, l’objectif est d’augmenter les performances tout en préservant l’exactitude.In PLINQ, the goal is to maximize performance while maintaining correctness. Une requête doit s’exécuter aussi rapidement que possible, mais toujours générer des résultats corrects.A query should run as fast as possible but still produce the correct results. Dans certains cas, l’exactitude requiert que l’ordre de la séquence source soit conservé ; toutefois, le classement peut coûter cher en calcul.In some cases, correctness requires the order of the source sequence to be preserved; however, ordering can be computationally expensive. Par conséquent, par défaut, PLINQ ne conserve pas l’ordre de la séquence source.Therefore, by default, PLINQ does not preserve the order of the source sequence. À cet égard, PLINQ est similaire à LINQ to SQLLINQ to SQL, mais pas à LINQ to Objects, qui conserve le classement.In this regard, PLINQ resembles LINQ to SQLLINQ to SQL, but is unlike LINQ to Objects, which does preserve ordering.

Pour remplacer le comportement par défaut, vous pouvez activer la conservation de l’ordre à l’aide de l’opérateur AsOrdered sur la séquence source.To override the default behavior, you can turn on order-preservation by using the AsOrdered operator on the source sequence. Vous pouvez désactiver la préservation de l’ordre plus loin dans la requête à l’aide de la méthode AsUnordered.You can then turn off order preservation later in the query by using the AsUnordered method. Ces deux méthodes permettent de traiter la requête en fonction des paramètres heuristiques, qui déterminent s’il faut exécuter la requête en parallèle ou de manière séquentielle.With both methods, the query is processed based on the heuristics that determine whether to execute the query as parallel or as sequential. Pour plus d’informations, consultez Fonctionnement de l’accélération dans PLINQ.For more information, see Understanding Speedup in PLINQ.

L’exemple suivant montre une requête parallèle non classée qui filtre tous les éléments qui correspondent à une condition, sans essayer de classer les résultats de quelque manière que ce soit.The following example shows an unordered parallel query that filters for all the elements that match a condition, without trying to order the results in any way.

var cityQuery = (from city in cities.AsParallel()
                 where city.Population > 10000
                 select city)
                   .Take(1000);
Dim cityQuery = From city In cities.AsParallel()
                Where City.Population > 10000
                Take (1000)

Cette requête ne produit pas nécessairement les 1 000 premières villes de la séquence source qui remplissent la condition, mais plutôt un ensemble de 1 000 villes qui remplissent la condition.This query does not necessarily produce the first 1000 cities in the source sequence that meet the condition, but rather some set of 1000 cities that meet the condition. Les opérateurs de requête PLINQ partitionnent la séquence source en plusieurs sous-séquences qui sont traitées comme des tâches simultanées.PLINQ query operators partition the source sequence into multiple subsequences that are processed as concurrent tasks. Si la conservation de l’ordre n’est pas spécifiée, les résultats de chaque partition sont remis à l’étape suivante de la requête dans un ordre arbitraire.If order preservation is not specified, the results from each partition are handed off to the next stage of the query in an arbitrary order. Par ailleurs, une partition peut donner un sous-ensemble de ses résultats avant de continuer à traiter les éléments restants.Also, a partition may yield a subset of its results before it continues to process the remaining elements. L’ordre résultant peut être différent à chaque fois.The resulting order may be different every time. Ceci ne peut pas être contrôlé par votre application, car cela dépend de la manière dont le système d’exploitation planifie les threads.Your application cannot control this because it depends on how the operating system schedules the threads.

L’exemple suivant remplace le comportement par défaut à l’aide de l’opérateur AsOrdered sur la séquence source.The following example overrides the default behavior by using the AsOrdered operator on the source sequence. Cela garantit que la méthode Take retourne les 1 000 premières villes de la séquence source qui remplissent la condition.This ensures that the Take method returns the first 1000 cities in the source sequence that meet the condition.

var orderedCities = (from city in cities.AsParallel().AsOrdered()
                     where city.Population > 10000
                     select city)
                    .Take(1000);

Dim orderedCities = From city In cities.AsParallel().AsOrdered()
                    Where City.Population > 10000
                    Take (1000)

Toutefois, cette requête ne s’exécute probablement pas aussi rapidement que la version non classée, car elle doit surveiller l’ordre d’origine dans toutes les partitions et s’assurer que le classement est cohérent au moment de la fusion.However, this query probably does not run as fast as the unordered version because it must keep track of the original ordering throughout the partitions and at merge time ensure that the ordering is consistent. Par conséquent, nous vous recommandons de n’utiliser AsOrdered que si c’est nécessaire, et uniquement pour les parties de la requête qui l’exigent.Therefore, we recommend that you use AsOrdered only when it is required, and only for those parts of the query that require it. Lorsque la conservation de l’ordre n’est plus nécessaire, utilisez AsUnordered pour la désactiver.When order preservation is no longer required, use AsUnordered to turn it off. L’exemple suivant obtient ce résultat en composant deux requêtes.The following example achieves this by composing two queries.

var orderedCities2 = (from city in cities.AsParallel().AsOrdered()
                      where city.Population > 10000
                      select city)
                        .Take(1000);

var finalResult = from city in orderedCities2.AsUnordered()
                  join p in people.AsParallel() on city.Name equals p.CityName into details
                  from c in details
                  select new { Name = city.Name, Pop = city.Population, Mayor = c.Mayor };

foreach (var city in finalResult) { /*...*/ }
Dim orderedCities2 = From city In cities.AsParallel().AsOrdered()
                     Where city.Population > 10000
                     Select city
                     Take (1000)

Dim finalResult = From city In orderedCities2.AsUnordered()
                  Join p In people.AsParallel() On city.Name Equals p.CityName
                  Select New With {.Name = city.Name, .Pop = city.Population, .Mayor = city.Mayor}

For Each city In finalResult
    Console.WriteLine(city.Name & ":" & city.Pop & ":" & city.Mayor)
Next

Notez que PLINQ conserve le classement d’une séquence produite par des opérateurs imposant un ordre pour le reste de la requête.Note that PLINQ preserves the ordering of a sequence produced by order-imposing operators for the rest of the query. En d’autres termes, les opérateurs tels que OrderBy et ThenBy sont traités comme s’ils étaient suivis d’un appel à AsOrdered.In other words, operators such as OrderBy and ThenBy are treated as if they were followed by a call to AsOrdered.

Opérateurs de requête et de classementQuery Operators and Ordering

Les opérateurs de requête suivants présentent la conservation de l’ordre dans toutes les opérations suivantes d’une requête, ou jusqu'à ce que AsUnordered soit appelée :The following query operators introduce order preservation into all subsequent operations in a query, or until AsUnordered is called:

dans certains cas, les opérateurs de requête PLINQ suivants peuvent exiger des séquences source classées pour produire des résultats corrects :The following PLINQ query operators may in some cases require ordered source sequences to produce correct results:

certains opérateurs de requête PLINQ se comportent différemment, selon que leur séquence source est classée ou non classée.Some PLINQ query operators behave differently, depending on whether their source sequence is ordered or unordered. Le tableau suivant répertorie ces opérateurs.The following table lists these operators.

OpérateurOperator Résultat lorsque la séquence source est classéeResult when the source sequence is ordered Résultat de la séquence source n’est pas classéeResult when the source sequence is unordered
Aggregate Sortie non déterministe pour les opérations non associatives ou non commutativesNondeterministic output for nonassociative or noncommutative operations Sortie non déterministe pour les opérations non associatives ou non commutativesNondeterministic output for nonassociative or noncommutative operations
All Non applicableNot applicable Non applicableNot applicable
Any Non applicableNot applicable Non applicableNot applicable
AsEnumerable Non applicableNot applicable Non applicableNot applicable
Average Sortie non déterministe pour les opérations non associatives ou non commutativesNondeterministic output for nonassociative or noncommutative operations Sortie non déterministe pour les opérations non associatives ou non commutativesNondeterministic output for nonassociative or noncommutative operations
Cast Résultats classésOrdered results Résultats non classésUnordered results
Concat Résultats classésOrdered results Résultats non classésUnordered results
Count Non applicableNot applicable Non applicableNot applicable
DefaultIfEmpty Non applicableNot applicable Non applicableNot applicable
Distinct Résultats classésOrdered results Résultats non classésUnordered results
ElementAt Retourner un élément spécifiéReturn specified element Élément arbitraireArbitrary element
ElementAtOrDefault Retourner un élément spécifiéReturn specified element Élément arbitraireArbitrary element
Except Résultats non classésUnordered results Résultats non classésUnordered results
First Retourner un élément spécifiéReturn specified element Élément arbitraireArbitrary element
FirstOrDefault Retourner un élément spécifiéReturn specified element Élément arbitraireArbitrary element
ForAll Exécute de façon non déterministe en parallèleExecutes nondeterministically in parallel Exécute de façon non déterministe en parallèleExecutes nondeterministically in parallel
GroupBy Résultats classésOrdered results Résultats non classésUnordered results
GroupJoin Résultats classésOrdered results Résultats non classésUnordered results
Intersect Résultats classésOrdered results Résultats non classésUnordered results
Join Résultats classésOrdered results Résultats non classésUnordered results
Last Retourner un élément spécifiéReturn specified element Élément arbitraireArbitrary element
LastOrDefault Retourner un élément spécifiéReturn specified element Élément arbitraireArbitrary element
LongCount Non applicableNot applicable Non applicableNot applicable
Min Non applicableNot applicable Non applicableNot applicable
OrderBy Réorganise la séquenceReorders the sequence Démarre une nouvelle section classéeStarts new ordered section
OrderByDescending Réorganise la séquenceReorders the sequence Démarre une nouvelle section classéeStarts new ordered section
Range Non applicable (même valeur par défaut que AsParallel)Not applicable (same default as AsParallel ) Non applicableNot applicable
Repeat Non applicable (même valeur par défaut que AsParallel)Not applicable (same default as AsParallel) Non applicableNot applicable
Reverse InverseReverses Sans effetDoes nothing
Select Résultats classésOrdered results Résultats non classésUnordered results
Select (indexé)Select (indexed) Résultats classésOrdered results Résultats non classés.Unordered results.
SelectMany Résultats classés.Ordered results. Résultats non classésUnordered results
SelectMany (indexé)SelectMany (indexed) Résultats classés.Ordered results. Résultats non classés.Unordered results.
SequenceEqual Comparaison classéeOrdered comparison Comparaison non classéeUnordered comparison
Single Non applicableNot applicable Non applicableNot applicable
SingleOrDefault Non applicableNot applicable Non applicableNot applicable
Skip Ignore les n premiers élémentsSkips first n elements Ignore les n élémentsSkips any n elements
SkipWhile Résultats classés.Ordered results. Non déterministe.Nondeterministic. Exécute SkipWhile dans l’ordre arbitraire actuelPerforms SkipWhile on the current arbitrary order
Sum Sortie non déterministe pour les opérations non associatives ou non commutativesNondeterministic output for nonassociative or noncommutative operations Sortie non déterministe pour les opérations non associatives ou non commutativesNondeterministic output for nonassociative or noncommutative operations
Take Prend les premiers éléments nTakes first n elements Prend tous les éléments nTakes any n elements
TakeWhile Résultats classésOrdered results Non déterministe.Nondeterministic. Exécute TakeWhile dans l’ordre arbitraire actuelPerforms TakeWhile on the current arbitrary order
ThenBy Complète OrderBySupplements OrderBy Complète OrderBySupplements OrderBy
ThenByDescending Complète OrderBySupplements OrderBy Complète OrderBySupplements OrderBy
ToArray Résultats classésOrdered results Résultats non classésUnordered results
ToDictionary Non applicableNot applicable Non applicableNot applicable
ToList Résultats classésOrdered results Résultats non classésUnordered results
ToLookup Résultats classésOrdered results Résultats non classésUnordered results
Union Résultats classésOrdered results Résultats non classésUnordered results
Where Résultats classésOrdered results Résultats non classésUnordered results
Where (indexé)Where (indexed) Résultats classésOrdered results Résultats non classésUnordered results
Zip Résultats classésOrdered results Résultats non classésUnordered results

Les résultats non classés ne sont pas mélangés de manière active ; aucune logique de classement spéciale ne leur est appliquée.Unordered results are not actively shuffled; they simply do not have any special ordering logic applied to them. Dans certains cas, une requête non classée peut conserver le classement de la séquence source.In some cases, an unordered query may retain the ordering of the source sequence. Pour les requêtes utilisant l’opérateur Select indexé, PLINQ garantit que les éléments de sortie arriveront dans l’ordre des indices croissant, mais n’offre aucune garantie quant aux index qui seront affectés aux éléments respectifs.For queries that use the indexed Select operator, PLINQ guarantees that the output elements will come out in the order of increasing indices, but makes no guarantees about which indices will be assigned to which elements.

Voir aussiSee also