Task.WaitAll方法与Parallel.Invoke方法

我有示例代码来比较Parallel方法和Task方法的处理时间。 这个实验的目标是了解它们是如何工作的。

所以我的问题是:

  1. 为什么Parallel工作得比Task快?
  2. 我的结果是否意味着我应该使用Parallel而不是Task?
  3. 我应该在哪里使用Task和Parallel?
  4. 使用Task与Parallel相比有什么好处?
  5. Task只是ThreadPool.QueueUserWorkItem方法的包装吗?

    public Task SomeLongOperation() { return Task.Delay(3000); } static void Main(string[] args) { Program p = new Program(); List tasks = new List(); 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(); } 

以下是我的处理结果: 结果

编辑:

更改后的代码如下所示:

  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(); 

我的新结果:

新结果

编辑2:当我用Parallel.Invoke替换代码为第一个,而Task.WaitAll替换为第二个时,情境已经被更改为cardinally。 现在Parallel比较慢。 这让我想到了我估计的不正确性。 我改变代码看起来像这样:

 Program p = new Program(); Task[] tasks = new Task[2]; Stopwatch sw = null; for (int i = 0; i  p.SomeLongOperation(), () => p.SomeLongOperation()); string res = sw.Elapsed.ToString(); Console.WriteLine("Parallel invoke results: " + res); sw.Stop(); } for (int i = 0; i  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(); } 

这是我的新结果:

在此处输入图像描述

在此处输入图像描述

现在我可以建议这个实验更加明确。 结果几乎相同。 有时并行,有时任务更快。 现在我的问题是:

1.我应该在哪里使用Task和Parallel?

2.与Parallel相比,使用Task有什么好处?

3. Task是ThreadPool.QueueUserWorkItem方法的包装吗?

欢迎提供任何可以澄清这些问题的有用信息。

编辑来自MSDN的 本文 :

Parallel和Task都是ThreadPool的包装器。 并行调用也等待所有任务完成。

与您的问题相关:

使用Task,Parallel或ThreadPool取决于执行并行任务时需要的控制粒度。 我个人习惯了Task.Factory.StartNew() ,但那是个人观点。 这与ThreadPool.QueueUserWorkItem()

附加信息:由于内部初始化,对Parallel.Invoke()和Task.Factory.StartNew()的第一次调用可能会变慢。

如果您启动非通用任务(即“void任务没有返回值”)并立即Wait它们,请改为使用Parallel.Invoke 。 您的意图立即向读者清楚。

使用任务如果:

  • 你不要马上等
  • 你需要回报价值
  • 你需要为被调用的方法提供参数
  • 您需要TaskCreationOptionsfunction
  • 您需要CancellationTokenTaskSchedulerfunction,并且不想使用ParallelOptions
  • 基本上,如果你想要更多的选择或控制

是的,您可以解决其中的一些问题,例如Parallel.Invoke(() => p.OpWithToken(CancellationToken)但这会混淆您的意图Parallel.Invoke(() => p.OpWithToken(CancellationToken)用于使用尽可能多的CPU功率进行大量工作。完成后,它不会死锁,你事先就知道了。


你的测试很可怕。 红旗将是你的长动作是等待3000毫秒,但你的测试需要不到十分之一毫秒。

 Task.Factory.StartNew(() => p.SomeLongOperation()); 

StartNew接受一个Action ,并在一个新的 Task执行它。 action () => SomeLongOperation()创建一个 Task创建此子任务(未完成)后,对SomeLongOperation()的调用将返回,并且Action已完成。 所以主要 Task已经在十分之一毫秒后完成,而你没有参考的两个子任务仍然在后台运行。 并行路径还创建两个子任务,它根本不跟踪,并返回。

正确的方法是tasks[0] = p.SomeLongOperation(); ,它为数组分配一个正在运行的任务。 然后WaitAll检查完成此任务。