我有示例代码来比较Parallel方法和Task方法的处理时间。这个实验的目标是了解它们是如何工作的。
所以我的问题是:
Task是否只是ThreadPool.QueueUserWorkItem方法的包装?
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();
}
以下是我的处理结果:
修改
将代码更改为如下所示:
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 < 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();
}
以下是我的新结果:
现在我可以建议这个实验更加明确。结果几乎相同。有时并行,有时任务更快。现在我的问题是:
1。我应该在哪里使用Task和Parallel?
2。使用Task与Parallel相比有什么好处?
第3。 Task只是ThreadPool.QueueUserWorkItem方法的包装吗?
欢迎任何可以澄清这些问题的有用信息。
答案 0 :(得分:8)
来自this article的MSDN编辑:
Parallel和Task都是ThreadPool的包装器。并行调用也等待所有任务完成。
与您的问题相关:
使用Task,Parallel或ThreadPool取决于执行并行任务时需要的控制粒度。我个人习惯Task.Factory.StartNew()
,但那是个人观点。这与ThreadPool.QueueUserWorkItem()
附加信息:由于内部初始化,对Parallel.Invoke()和Task.Factory.StartNew()的第一次调用可能会变慢。
答案 1 :(得分:3)
如果您启动非通用任务(即&#34; void任务没有返回值&#34;)并立即启动Wait
,请改用Parallel.Invoke
。您的意图立即为读者所知。
在以下情况下使用任务:
TaskCreationOptions
功能CancellationToken
或TaskScheduler
个功能,并且不想使用ParallelOptions
是的,你可以解决其中一些问题,例如: Parallel.Invoke(() => p.OpWithToken(CancellationToken)
但这会混淆你的意图。 Parallel.Invoke
用于尽可能多地使用CPU功率进行大量工作。它完成了,它没有死锁,你提前知道了。
你的测试很可怕。红旗将是你的长动作是等待3000毫秒,但你的测试只需不到十分之一毫秒。
Task.Factory.StartNew(() => p.SomeLongOperation());
StartNew需要Action
,并在新的主 Task
中执行此操作。动作() => SomeLongOperation()
会创建子任务 Task
。在此子任务创建(未完成)后,对SomeLongOperation()
的调用将返回,操作完成。所以 main Task
已经在十分之一毫秒后完成,而你没有引用的两个子任务仍然在后台运行。并行路径也是创建两个子任务,它根本不跟踪,然后返回。
正确的方法是tasks[0] = p.SomeLongOperation();
,它为数组分配一个正在运行的任务。然后WaitAll
检查完成此任务。