为什么Task.Factory.StartNew会在Task.Run没有的情况下立即返回?

时间:2017-01-22 07:43:52

标签: c# task-parallel-library

请考虑以下代码段:

<a-video src="#penguin-sledding" width="16" height="9" position="0 0 -20"></a-video> 

这可以按预期工作,执行时间为4.000毫秒。但是,如果我与Task[] tasks = new Task[4]; for (var i = 0; i < tasks.Length; ++i) { tasks[i] = Task.Run(async () => { await Task.Delay(4000); }); } for (var i = 0; i < tasks.Length; ++i) await tasks[i]; Console.WriteLine("Done!"); 交换Task.Run,则只需0.006毫秒!

任何人都可以解释原因吗?

3 个答案:

答案 0 :(得分:5)

好的,我在阅读https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/

后自己找到了答案
  

通过在这里使用async关键字,编译器将映射它   委托成为Func<Task<int>>:调用委托将返回   Task<int>表示此次通话的最终完成情况。和   由于代表是Func<Task<int>>TResultTask<int>,因此   “t”的类型将是Task<Task<int>>,而不是Task<int>

所以这段代码按预期工作:

Task[] tasks = new Task[4];
for (var i = 0; i < tasks.Length; ++i) {
    tasks[i] = Task.Factory.StartNew(async () =>
    {
        await Task.Delay(4000);
    });
}
for (var i = 0; i < tasks.Length; ++i)
    await await (tasks[i] as Task<Task>);

Console.WriteLine("Done!");

也可以使用Unwrap实现:

Task[] tasks = new Task[4];
for (var i = 0; i < tasks.Length; ++i) {
    tasks[i] = Task.Factory.StartNew(async () =>
    {
        await Task.Delay(4000);
    }).Unwrap();
}
for (var i = 0; i < tasks.Length; ++i)
    await tasks[i];

Console.WriteLine("Done!");

答案 1 :(得分:5)

  

任何人都可以解释原因吗?

简而言之,StartNew无法理解async代表。

因此,when your delegate returns an incomplete task at its first awaitStartNew会看到委托退出并认为其工作已完成。这就是它在这里返回Task<Task>的原因。 Task.Run具有处理异步委托的特殊逻辑,自动解包内部任务。

这只是将StartNew与异步代码一起使用的缺陷之一;我在我的博文StartNew is Dangerous中详细介绍了这个以及其他内容。

答案 2 :(得分:3)

答案是here

  

两种方法之间的行为存在差异:   默认情况下,Task.Run(Action)不允许以子任务启动   要附加到的TaskCreationOptions.AttachedToParent选项   当前的Task实例,而StartNew(Action)确实

因此,Task.Run将等待执行完成,Task.Factory.StartNew会立即返回任务。

相关问题