关于 Task.Start() 、 Task.Run() 和 Task.Factory.StartNew() 的使用

Posted

技术标签:

【中文标题】关于 Task.Start() 、 Task.Run() 和 Task.Factory.StartNew() 的使用【英文标题】:Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew() 【发布时间】:2015-06-23 23:02:34 【问题描述】:

我刚刚看到了 3 个关于 TPL 使用的例程,它们做同样的工作;这是代码:

public static void Main()

    Thread.CurrentThread.Name = "Main";

    // Create a task and supply a user delegate by using a lambda expression. 
    Task taskA = new Task( () => Console.WriteLine("Hello from taskA."));
    // Start the task.
    taskA.Start();

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '0'.", 
                  Thread.CurrentThread.Name);
    taskA.Wait();


public static void Main()

    Thread.CurrentThread.Name = "Main";

    // Define and run the task.
    Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '0'.", 
                      Thread.CurrentThread.Name);
    taskA.Wait();


public static void Main()

    Thread.CurrentThread.Name = "Main";

    // Better: Create and start the task in one operation. 
    Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '0'.", 
                    Thread.CurrentThread.Name);

    taskA.Wait();                  

我只是不明白为什么 MS 提供了 3 种不同的方式在 TPL 中运行作业,因为它们都工作相同:Task.Start()Task.Run()Task.Factory.StartNew()

告诉我,Task.Start()Task.Run()Task.Factory.StartNew() 是否都用于相同的目的,或者它们有不同的意义?

什么时候应该使用Task.Start(),什么时候应该使用Task.Run(),什么时候应该使用Task.Factory.StartNew()

请通过示例帮助我根据场景详细了解它们的实际用法,谢谢。

【问题讨论】:

有一个old article explaining that here 和here for the newer Task.Run - 也许这会回答你的问题;) Here 是 Task.Start 实际有用的示例。 What is the difference between Task.Run() and Task.Factory.StartNew()的可能重复 【参考方案1】:

Task.Run 是带有特定安全参数的Task.Factory.StartNew 的简写:

Task.Factory.StartNew(
    action, 
    CancellationToken.None, 
    TaskCreationOptions.DenyChildAttach, 
    TaskScheduler.Default);

它是在 .Net 4.5 中添加的,以帮助越来越频繁地使用 async 并将工作卸载到 ThreadPool

Task.Factory.StartNew(在 .Net 4.0 中添加了 TPL)更加健壮。仅当 Task.Run 不够时才应使用它,例如当您想使用 TaskCreationOptions.LongRunning 时(尽管当委托是异步的时它是不必要的。更多关于我的博客:LongRunning Is Useless For Task.Run With async-await)。更多关于Task.Factory.StartNewTask.Run vs Task.Factory.StartNew

永远不要创建Task 并调用Start(),除非您找到非常好的理由这样做。仅当您有一些需要创建任务但不安排它们的部分和另一个需要安排但不创建的部分时才应该使用它。这几乎不是一个合适的解决方案,而且可能很危险。更多内容"Task.Factory.StartNew" vs "new Task(...).Start"

总之,主要使用Task.Run,如果必须使用Task.Factory.StartNew,永远不要使用Start

【讨论】:

你说“永远不要创建任务并调用 Start()”将我重定向到任何好的文章,这将表明可能由 Task.Start() 引起。我需要详细信息,因为你说要避免它。感谢您的回复。 你在谈论这个链接blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx?? @Mou Task.Start 主要用于继承类型。 @Mou 效率低下,因为它需要同步以确保只调用一次。其他选项没有。 @Mou 您可能应该阅读解释此问题的帖子blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx【参考方案2】:

简答

如果您不使用嵌套子任务并且总是希望您的任务在线程池上执行,最好使用Task.Run

长答案:

Task.RunTask.Factory.StartNew 都支持创建和调度 Task 对象,因此我们不需要创建 Task 并调用 Start()

Task.Run(action);

相当于:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

Task.Factory.StartNew(action);

相当于:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

Task.Run 使用TaskCreationOptions.DenyChildAttach 表示子任务不能附加到父任务,它使用TaskScheduler.Default 表示在线程池上运行任务的将始终用于运行任务。

Task.Factory.StartNew 使用TaskScheduler.Current 表示当前线程的调度程序,它可能是TaskScheduler.Default,但并非总是如此。

【讨论】:

以上是关于关于 Task.Start() 、 Task.Run() 和 Task.Factory.StartNew() 的使用的主要内容,如果未能解决你的问题,请参考以下文章

Task.Start/Wait 和 Async/Await 有啥区别?

Task用法-任务等待wait

并行编程 - Task任务

多线程--Task,等待用户输入AutoResetEvent

Activiti7工作流引擎:数据库表结构

异步多线程Task