3

以下约定之间的主要区别是什么。

第一的:

Task myTask = new Task(()=>
{
     // executable statements
});
myTask.Start();

第二:

Task.Run(()=>
{
  // executable statements
});

第三:

  Task.Factory.StartNew(() =>
  {
       // executable statements
  });
4

1 回答 1

8

首先,此信息可通过简单的 google 获得。

A. 从​​ MSDN "Task.Factory.StartNew" 与 "new Task(...).Start"

使用 TPL,有多种方法可以创建和启动新任务。一种方法是使用 task 的构造函数,然后调用 Start 方法,例如

new Task(...).Start();

另一种是使用 StartNew 方法TaskFactory,例如

Task.Factory.StartNew(...);

这就引出了一个问题……您何时以及为什么要使用一种方法而不是另一种方法?

一般来说,我总是建议使用Task.Factory.StartNew,除非特定情况提供了使用构造函数后跟 Start 的令人信服的理由。我推荐这个有几个原因。一方面,它通常更有效。例如,我们在 TPL 中非常小心,以确保当从多个线程同时访问任务时,会发生“正确”的事情。ATask只执行一次,这意味着我们需要确保从多个线程同时多次调用任务的 Start 方法只会导致任务被调度一次。这需要同步,而同步是有代价的。如果使用任务的构造函数构造任务,则在调用Start方法,因为我们需要防止另一个线程同时调用 Start。但是,如果您使用Task.Factory.StartNew,我们知道在我们将任务引用交还给您的代码时,该任务已经安排好了,这意味着线程不再可能竞相调用 Start,因为每次调用Start都会失败。因此,StartNew我们可以避免额外的同步成本,并采用更快的路径来调度任务。

B. 从MSDN Task.Run 与 Task.Factory.StartNew

因此,在 .NET Framework 4.5 开发者预览版中,我们引入了新Task.Run方法。这绝不会过时Task.Factory.StartNew,而是应该简单地认为是一种Task.Factory.StartNew无需指定一堆参数的快速使用方式。这是一条捷径。实际上,Task.Run实际上是按照与 for 相同的逻辑来实现的Task.Factory.StartNew,只是传入了一些默认参数。当你传递一个Actionto 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是您的朋友。

我希望这有帮助。

于 2013-04-26T11:20:50.983 回答