De la tâche.WaitAll méthode vs Parallèle.Méthode Invoke
J'ai un exemple de code pour comparer les temps de traitement en Parallèle de l'approche et de l'approche de la Tâche. Le but de cette expérience est de comprendre comment fonctionnent-ils.
Donc mes questions sont:
- Pourquoi Parallèle travaillé plus rapide, puis la Tâche?
- Faire de mon résultat signifie que je dois utiliser en Parallèle au lieu de la Tâche?
- Où dois-je utiliser les groupes de travail et où Parallèle?
- Quels sont les avantages de l'utilisation de la Tâche en comparaison Parallèle?
-
Ne Tâche est juste une enveloppe pour le pool de threads.QueueUserWorkItem méthode?
public Task SomeLongOperation() { return Task.Delay(3000); } static void Main(string[] args) { Program p = new Program(); List<Task> tasks = new List<Task>(); tasks.Add(Task.Factory.StartNew(() => p.SomeLongOperation())); tasks.Add(Task.Factory.StartNew(() => p.SomeLongOperation())); var arr = tasks.ToArray(); Stopwatch sw = Stopwatch.StartNew(); Task.WaitAll(arr); Console.WriteLine("Task wait all results: " + sw.Elapsed); sw.Stop(); sw = Stopwatch.StartNew(); Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation()); Console.WriteLine("Parallel invoke results: " + sw.Elapsed); sw.Stop(); Console.ReadKey(); }
Voici mes résultats du traitement:
EDIT:
Code modifié pour ressembler à ceci:
Program p = new Program();
Task[] tasks = new Task[2];
Stopwatch sw = Stopwatch.StartNew();
tasks[0] = Task.Factory.StartNew(() => p.SomeLongOperation());
tasks[1] = Task.Factory.StartNew(() => p.SomeLongOperation());
Task.WaitAll(tasks);
Console.WriteLine("Task wait all results: " + sw.Elapsed);
sw.Stop();
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
Console.WriteLine("Parallel invoke results: " + sw.Elapsed);
sw.Stop();
Mes nouveaux résultats:
EDIT 2:
Quand j'ai remplacé le code en Parallèle.Invoquer pour être la première et Tâche.WaitAll d'être le second, la situation a changé foncièrement. Maintenant Parallèle est plus lent. Il me fait penser à l'inexactitude de mes estimations. J'ai changé le code ressemble à ceci:
Program p = new Program();
Task[] tasks = new Task[2];
Stopwatch sw = null;
for (int i = 0; i < 10; i++)
{
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
string res = sw.Elapsed.ToString();
Console.WriteLine("Parallel invoke results: " + res);
sw.Stop();
}
for (int i = 0; i < 10; i++)
{
sw = Stopwatch.StartNew();
tasks[0] = Task.Factory.StartNew(() => p.SomeLongOperation());
tasks[1] = Task.Factory.StartNew(() => p.SomeLongOperation());
Task.WaitAll(tasks);
string res2 = sw.Elapsed.ToString();
Console.WriteLine("Task wait all results: " + res2);
sw.Stop();
}
Et voici mes nouveaux résultats:
Maintenant je peux suggérer que cette expérience est beaucoup plus clair. Les résultats sont presque les mêmes. Parfois Parallèle, et parfois la Tâche est plus rapide. Maintenant mes questions sont:
1. Où dois-je utiliser les groupes de travail et où Parallèle?
2. Quels sont les avantages de l'utilisation de la Tâche en comparaison Parallèle?
3. Ne Tâche est juste une enveloppe pour le pool de threads.QueueUserWorkItem méthode?
Toute info utile qui peut aider à clarifier ces questions sont les bienvenues.
- les tâches.Ajouter(Tâche.Usine.StartNew(() => p.SomeLongOperation())); déjà commencé, mais à ce moment, le chronomètre n'a pas commencé à compter encore!
- Comment dois-je changer le code afin de rendre cette expérience plus clair?
- Déplacer au-dessus de la startnew()
- BTW: vous pouvez appeler sw.Écoulé.Les tiques ou sw.Écoulé.TotalMilliseconds, au lieu de " sw.Écoulé", le précédent 00:00... n'est pas utile.
- J'ai déménagé startnew méthode tâches ci-dessus.Ajouter(...). Maintenant les tâches beaucoup plus lent alors que c'était.
- Peut-être il existe une surcharge due à l'appel de la méthode ToArray?
Vous devez vous connecter pour publier un commentaire.
MODIFIER en tant que de cet article de MSDN:
À la fois Parallèle et de la Tâche sont des wrappers pour le pool de threads. En parallèle invoquer attend jusqu'à ce que toutes les tâches sont terminées.
Liées à vos questions:
À l'aide de la Tâche, en Parallèle ou en pool de threads dépend de la granularité de contrôle que vous avez besoin d'avoir sur l'exécution de vos tâches en parallèle. Personnellement, je suis habitué à
Task.Factory.StartNew()
, mais c'est un avis personnel. La même chose se rapporte àThreadPool.QueueUserWorkItem()
Informations complémentaires: le premier appel à La Parallèle.Invoke() et de la Tâche.Usine.StartNew() peut-être plus lent en raison de l'initialisation.
SomeLongOperation()
?Task.Factory.StartNew()
blog.stephencleary.com/2013/08/startnew-is-dangerous.htmlSi vous commencez à nongeneric Tâches(c'est à dire "nul Tâches sans valeur de retour") et immédiatement
Wait
pour eux, l'utilisationParallel.Invoke
à la place. Votre intention est évidente pour le lecteur.Utilisation de Tâches si:
TaskCreationOptions
fonctionnalitéCancellationToken
ouTaskScheduler
fonctionnalité et ne souhaitez pas utiliserParallelOptions
Oui, vous pouvez obtenir autour de certains de ces, par exemple,
Parallel.Invoke(() => p.OpWithToken(CancellationToken)
mais qui dissimule votre intention.Parallel.Invoke
est de faire un tas de travail à l'aide de plus de CPU que possible. Il se fait, il n'a pas de blocage, et vous savez à l'avance.Votre test est horrible mais. Le drapeau rouge serait que votre durée d'action est d'attendre 3000 millisecondes, mais vos tests en prendre moins d'un dixième de milliseconde.
StartNew prend un
Action
, et s'exécute dans une nouvelle principalTask
. L'action() => SomeLongOperation()
crée un sous-tâcheTask
. Après cette sous-tâche est créé (pas terminé), l'appel àSomeLongOperation()
retourne, et la Action est fait. Ainsi, le principalTask
est déjà terminée après un dixième de milliseconde, alors que les deux sous-tâches que vous n'avez aucune référence à sont toujours en cours d'exécution en arrière-plan. Le chemin Parallèle crée également deux sous-tâches, il n'est pas suivi du tout, et les retours.La façon correcte serait
tasks[0] = p.SomeLongOperation();
, qui assigne une tâche en cours d'exécution dans le tableau. PuisWaitAll
vérifie la finition de cette tâche.