Jac*_*Lee 3 .net c# asynchronous async-await
var L1 =
Task.Run(() =>
{
return Task.Run(() =>
{
return Task.Run(() =>
{
return Task.Run(() =>
{
return new Dummy();
});
});
});
});
var L2 =
Task.Run(async () =>
{
return await Task.Run(async () =>
{
return await Task.Run(async () =>
{
return await Task.Run(async () =>
{
return new Dummy();
});
});
});
});
var L3 =
Task.Run(async () =>
{
return Task.Run(async () =>
{
return Task.Run(async () =>
{
return Task.Run(async () =>
{
return new Dummy();
});
});
});
});
var r1 = L1.Result;
var r2 = L2.Result;
var r3 = L3.Result;
Run Code Online (Sandbox Code Playgroud)
================================================== ====================
乍一看,L1,L2和L3都看起来像
Task<Task<Task<Task<Dummy>>>>
转出来,L1和L2都很简单Task<Dummy>
所以,我查找MSDN for Task.Run
(我的重载Task.Run是:Task.Run<TResult>(Func<Task<TResult>>)
)
MSDN说:
返回值是:一个Task(TResult),表示函数返回的Task(TResult)的代理.
它还在备注中说:
Run<TResult>(Func<Task<TResult>>)
语言编译器使用该方法来支持async和await关键字.它无意直接从用户代码调用.
因此,看起来我不应该在我的代码中使用这个重载的Task.Run,
如果我这样做,编译器将剥离额外的层Task<Task<Task<...<TResult>>>>
并简单地给你一个Task<TResult>
如果你鼠标悬停在L1和L2上,它告诉你它是Task<Dummy>
,不是我的
预期Task<Task<Task<Task<Dummy>>>>
到目前为止这么好,直到我看到L3
L3看起来几乎与L1和L2完全相同.不同之处在于:
L3只有async
关键字,而不是await
L1和L2,其中L1既没有它们也有L2都有它们
令人惊讶的是,现在认为L3 Task<Task<Task<Task<Dummy>>>>
与L1和L2不同,两者都被考虑在内Task<Dummy>
我的问题:
1.
是什么导致编译器以不同于L1和L2的方式处理L3.为什么简单地添加'async'
到L1(或await
从L2中删除)会导致编译器对其进行不同的处理?
2.
如果将更多Task.Run级联到L1/L2/L3,则Visual Studio崩溃.我正在使用VS2013,如果我级联5层或更多层的Task.Run,它会崩溃.4层是我能得到的最好的,这就是为什么我使用4层作为我的例子.只有我吗 ?编译器在翻译Task.Run时会发生什么?
谢谢
是什么导致编译器以不同于L1和L2的方式处理L3.为什么简单地将"async"添加到L1(或从L2中删除等待)会导致编译器对其进行不同的处理?
因为async
并且await
更改了lambda表达式中的类型.您可以将其async
视为"添加" Task<>
包装器,并将其await
视为"删除" Task<>
包装器.
只需考虑最里面调用中涉及的类型.首先,L1:
return Task.Run(() =>
{
return new Dummy();
});
Run Code Online (Sandbox Code Playgroud)
() => { return new Dummy(); }
is 的类型Func<Dummy>
,以及该重载Task.Run
的返回类型是Task<Dummy>
.
所以() => ###Task<Dummy>###
is 的类型Func<Task<Dummy>>
,调用不同的重载Task.Run
,返回类型为Task<Dummy>
.等等.
现在考虑L2:
return await Task.Run(async () =>
{
return new Dummy();
});
Run Code Online (Sandbox Code Playgroud)
类型async () => { return new Dummy(); }
是Func<Task<Dummy>>
,所以该重载Task.Run
的返回类型是Task<Dummy>
.
async () => await ###Task<Dummy>###
is 的类型Func<Task<Dummy>>
,因此它调用结果类型为的相同重载Task.Run
Task<Dummy>
.等等.
最后,L3:
return Task.Run(async () =>
{
return new Dummy();
});
Run Code Online (Sandbox Code Playgroud)
类型async () => { return new Dummy(); }
又是Func<Task<Dummy>>
,所以该重载Task.Run
的返回类型是Task<Dummy>
.
类型async () => { return ###Task<Dummy>### }
是Func<Task<Task<Dummy>>>
.请注意嵌套任务.因此,再次调用相同的重载Task.Run
,但它的返回类型是Task<Task<Dummy>>
这次.
现在,您只需重复每个级别.类型async () => { return ###Task<Task<Dummy>>### }
是Func<Task<Task<Task<Dummy>>>>
.在的同一超载Task.Run
被再次调用,但它的返回类型是Task<Task<Task<Dummy>>>
这个时候.等等.
如果您将更多Task.Run级联到L1/L2/L3,则Visual Studio会崩溃.我正在使用VS2013,如果我级联5层或更多层的Task.Run,它会崩溃.4层是我能得到的最好的,这就是为什么我使用4层作为我的例子.只有我吗 ?编译器在翻译Task.Run时会发生什么?
谁在乎?没有现实世界的代码可以做到这一点.众所周知的场景对于编译器来说在合理的时间范围内难以处理; 在方法重载解析中使用lambda表达式是其中之一.使用lambda表达式的嵌套调用使编译器的工作量指数级增加.
归档时间: |
|
查看次数: |
261 次 |
最近记录: |