请考虑以下代码段:
<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毫秒!
任何人都可以解释原因吗?
答案 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>>
,TResult
是Task<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 await
,StartNew
会看到委托退出并认为其工作已完成。这就是它在这里返回Task<Task>
的原因。 Task.Run
具有处理异步委托的特殊逻辑,自动解包内部任务。
这只是将StartNew
与异步代码一起使用的缺陷之一;我在我的博文StartNew
is Dangerous中详细介绍了这个以及其他内容。
答案 2 :(得分:3)
答案是here
两种方法之间的行为存在差异: 默认情况下,Task.Run(Action)不允许以子任务启动 要附加到的TaskCreationOptions.AttachedToParent选项 当前的Task实例,而StartNew(Action)确实
因此,Task.Run
将等待执行完成,Task.Factory.StartNew
会立即返回任务。