【问题标题】:Questions regarding Task Programming关于任务编程的问题
【发布时间】:2013-04-26 21:48:48
【问题描述】:
以下约定之间的主要区别是什么。
第一:
Task myTask = new Task(()=>
{
// executable statements
});
myTask.Start();
第二:
Task.Run(()=>
{
// executable statements
});
第三:
Task.Factory.StartNew(() =>
{
// executable statements
});
【问题讨论】:
标签:
c#
task-parallel-library
c#-5.0
【解决方案1】:
首先,此信息可通过简单的 google 获得。
A.来自MSDN "Task.Factory.StartNew" vs "new Task(...).Start"
使用 TPL,有多种方法可以创建和启动新任务。一种方法是使用 task 的构造函数,然后调用 Start 方法,例如
new Task(...).Start();
另一种是使用TaskFactory的StartNew方法,例如
Task.Factory.StartNew(...);
这引出了一个问题……您何时以及为什么要使用一种方法而不是另一种方法?
一般来说,我总是推荐使用Task.Factory.StartNew,除非特定情况提供了使用构造函数后跟Start 的令人信服的理由。我推荐这个有几个原因。一方面,它通常更有效。例如,我们在 TPL 中非常小心,以确保当从多个线程同时访问任务时,会发生“正确”的事情。 Task 只执行一次,这意味着我们需要确保从多个线程同时多次调用任务的 Start 方法只会导致任务被调度一次。这需要同步,而同步是有代价的。如果使用任务的构造函数构造任务,则在调用Start 方法时会支付此同步成本,因为我们需要防止另一个线程同时调用 Start。但是,如果您使用Task.Factory.StartNew,我们知道在我们将任务引用交还给您的代码时,该任务已经安排好了,这意味着线程不再可能竞相调用 Start,因为每次调用Start 将失败。因此,对于StartNew,我们可以避免额外的同步成本,并采用更快的路径来调度任务。
B.来自MSDN Task.Run vs Task.Factory.StartNew
因此,在 .NET Framework 4.5 开发者预览版中,我们引入了新的 Task.Run 方法。这绝不会过时Task.Factory.StartNew,而是应该简单地认为是一种使用Task.Factory.StartNew 的快速方法,而无需指定一堆参数。这是一条捷径。事实上,Task.Run实际上是按照与Task.Factory.StartNew相同的逻辑实现的,只是传入了一些默认参数。当您将Action 传递给Task.Run 时:
Task.Run(someAction);
这完全等同于:
Task.Factory.StartNew(someAction,
CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
通过这种方式,Task.Run 可以而且应该用于最常见的情况,即简单地卸载一些要在 ThreadPool 上处理的工作(TaskScheduler.Default 的目标)。这并不意味着Task.Factory.StartNew 将不再被使用;离得很远。 Task.Factory.StartNew 仍然有许多重要(尽管更高级)的用途。您可以控制TaskCreationOptions 来了解任务的行为方式。您可以控制任务应该在哪里排队和运行的调度程序。您可以使用接受对象状态的重载,这对于性能敏感的代码路径可用于避免闭包和相应的分配。不过,对于简单的情况,Task.Run 是您的朋友。
我希望这会有所帮助。