我刚看到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()
?
请帮助我通过示例非常详细地了解它们的实际用法,谢谢。
答案 0 :(得分:141)
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.Run vs Task.Factory.StartNew
Task.Factory.StartNew
的更多信息
除非您找到一个非常充分的理由,否则不要创建Task
并致电Start()
。只有在某些部分需要创建任务而不是计划任务而另一部分计划而不创建时,才应该使用它。这几乎从来都不是一个合适的解决方案,而且可能很危险。更多"Task.Factory.StartNew" vs "new Task(...).Start"
总之,主要使用Task.Run
,如果必须,请使用Task.Factory.StartNew
,永远不要使用Start
。
答案 1 :(得分:4)
简短答案:
如果您不使用嵌套子级任务,并且始终希望在线程池上执行任务,则最好使用Task.Run
。
详细答案:
Task.Run
和Task.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
,但并非总是如此。