2010-03-08 29 views
3

J'essaie de comprendre comment le parallélisme pourrait fonctionner en utilisant PLINQ, étant donné l'exécution retardée. Voici un exemple simple.PLINQ retardé l'exécution

string[] words = { "believe", "receipt", "relief", "field" }; 
bool result = words.AsParallel().Any(w => w.Contains("ei")); 

Avec LINQ, je me attends à l'exécution pour atteindre la valeur de la « réception », et va, sans exécuter la requête pour le repos des valeurs.

Si nous faisons cela en parallèle, l'évaluation de "relief" peut avoir commencé avant que le résultat de "réception" soit revenu. Mais une fois que la requête sait que "réception" va provoquer un vrai résultat, les autres threads céderont-ils immédiatement? Dans mon cas, c'est important parce que le test "any" peut être très coûteux, et je voudrais libérer les processeurs pour l'exécution d'autres tâches.

Répondre

4

Malheureusement, les autres threads ne "céderont" pas immédiatement.

Dès que Any() trouve un élément valide, le planificateur PLINQ arrête de planifier de nouveaux threads pour vérifier les nouveaux éléments. Tous les partitions existantes recevront également une demande d'annulation, ce qui empêchera ces partitions d'appeler Any() sur un autre élément.

Cependant, les discussions qui sont en cours d'exécution l'expression lambda au sein votre méthode Any() sera toujours l'exécution, car il n'y a aucun moyen pour eux de savoir qu'un autre thread a réussi. Cela empêchera les nouveaux threads d'appeler Any(), mais n'annulera pas tous les threads dans un délégué "très cher".

Sur une note latérale:

PLINQ, contrairement aux objets LINQ, n'utilise pas vraiment l'exécution différée. Lorsque vous appelez AsParallel() sur un IEnumerable<T>, le ParallelQuery<T> qui est généré commencera réellement à traiter votre routine en parallèle. L'exécution différée réduirait considérablement l'efficacité de PLINQ, car il serait impossible de planifier, en parallèle, sans créer les partitions de travail et planifier à l'avance.


Edit:

Après avoir réfléchi à ce sujet - si votre lambda est très cher, vous voudrez peut-être envisager d'utiliser un CancellationToken. J'ai blogué, en détail, sur how cancellation in PLINQ works. En général, vous devez simplement utiliser un jeton et appeler le ThrowIfCancellationRequested(). Cependant, vous pouvez également utiliser un CancellationToken et cocher IsCancellationRequested, ce qui vous permettra de faire sortir votre lambda plus tôt, ce qui vous permettra d'arrêter le traitement en arrière-plan ...

+0

http://msdn.microsoft.com/en-us/library/dd997425(VS.100).aspx dit principes d'exécution différée sont toujours en jeu avec PLINQ ... pouvez-vous clarifier un peu ce que vous voulez dire dans votre point latéral? – tbischel

+0

@tbischel: Ils le font, et ils ne le font pas ... Ce commentaire est légèrement trompeur. La différence est que, dans LINQ, chaque élément est seulement exécuté comme demandé (différé). Dans PLINQ, dès que vous faites la demande FIRST, un 'Partitioner ' est configuré, ce qui commence à planifier votre travail à plusieurs threads. Les résultats cumulés finaux ne sont pas repoussés jusqu'à la demande, mais le traitement se produit avant la demande d'un élément. (Si vous demandez l'élément 1 des résultats, les éléments 1, 2, 3 et 4 peuvent tous être programmés et commencer à "travailler" immédiatement ...) –