La première est une bien meilleure option.
Parallel.ForEach, en interne, utilise un Partitioner<T>
pour distribuer votre collection en éléments de travail. Il ne fera pas une tâche par article, mais plutôt en lots pour réduire les frais généraux impliqués.
La deuxième option prévoit un seul Task
article par article dans votre collection. Bien que les résultats soient (presque) les mêmes, cela entraînera beaucoup plus de frais généraux que nécessaire, en particulier pour les grandes collections, et ralentira les temps d'exécution globaux.
FYI - Le partitionneur utilisé peut être contrôlé en utilisant les surcharges appropriées pour Parallel.ForEach , si vous le souhaitez. Pour plus de détails, voir Partitionneurs personnalisés sur MSDN.
La principale différence, lors de l'exécution, est que la seconde agira de manière asynchrone. Cela peut être dupliqué en utilisant Parallel.ForEach en faisant:
Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));
En faisant cela, vous profitez toujours des partitionneurs, mais ne bloquez pas tant que l'opération n'est pas terminée.
J'ai fait une petite expérience de l'exécution d'une méthode "1 000 000 000 (un milliard)" fois avec "Parallel.For" et une avec des objets "Tâche".
J'ai mesuré le temps processeur et trouvé Parallel plus efficace. Parallel.For divise votre tâche en petits éléments de travail et les exécute sur tous les cœurs en parallèle de manière optimale. Lors de la création de nombreux objets de tâche (FYI TPL utilisera le pool de threads en interne), chaque exécution de chaque tâche se déplacera, ce qui créera plus de stress dans la boîte, comme le montre l'expérience ci-dessous.
J'ai également créé une petite vidéo qui explique le TPL de base et a également montré comment Parallel.For utilise votre noyau plus efficacement http://www.youtube.com/watch?v=No7QqSc5cl8 par rapport aux tâches et threads normaux.
Expérience 1
Expérience 2
la source
Mehthod1()
dans cet exemple?Parallel.ForEach optimisera (peut même ne pas démarrer de nouveaux threads) et bloquera jusqu'à ce que la boucle soit terminée, et Task.Factory créera explicitement une nouvelle instance de tâche pour chaque élément, et retournera avant qu'ils ne soient terminés (tâches asynchrones). Parallel.Foreach est beaucoup plus efficace.
la source
À mon avis, le scénario le plus réaliste est lorsque les tâches doivent être exécutées de manière intensive. L'approche de Shivprasad se concentre davantage sur la création d'objets / l'allocation de mémoire que sur le calcul lui-même. J'ai fait une recherche appelant la méthode suivante:
L'exécution de cette méthode prend environ 0,5 seconde.
Je l'ai appelé 200 fois en utilisant Parallel:
Ensuite, je l'ai appelé 200 fois en utilisant l'ancienne méthode:
Le premier cas a été achevé en 26656 ms, le second en 24478 ms. Je l'ai répété plusieurs fois. Chaque fois que la deuxième approche est marginalement plus rapide.
la source