【问题标题】:Async lambda vs regular lambda in Task.Run [duplicate]Task.Run 中的异步 lambda 与常规 lambda [重复]
【发布时间】:2018-12-09 04:56:25
【问题描述】:
假设我有一个方法可以运行带有一些异步调用的连续 while 循环
async Task MethodA(){
while(true){ perform async/await operations }
}
有什么区别:
Task.Run( () => MethodA(); }
Task.Run( async () => await MethodA(); }
如果有区别,什么时候比另一个更有用?
【问题讨论】:
标签:
c#
task-parallel-library
【解决方案1】:
有很大的不同。 MethodA() 返回 Task。如果您不等待 Task 的结果,则处理将照常继续。
即
Task.Run( () => MethodA(); }
MethodA() 在内部遇到等待时立即返回Task。 lambda 现在完成了(它调用了MethodA() 并获得了返回值),所以Task.Run() 将把它自己的任务标记为完成,线程将被释放。
Task.Run( async () => await MethodA(); }
lambda 是异步的,您正在等待MethodA() 的真实结果。 Task.Run() 返回的 Task 在 MethodA() 完成之前不会完成。
【解决方案2】:
根据 Stephen Cleary 在回答 https://stackoverflow.com/a/19098209/3107892 中的回答以及他的链接博客文章,唯一的区别是第二个创建了一个状态机。在这里,您可以使用第一种情况而没有任何缺点。
您可以遵循以下准则:
- 默认不省略。使用 async 和 await 获得自然、易读的代码;
- 当方法只是传递或重载时,请考虑省略;
- 如果您希望方法显示在堆栈跟踪中,请不要省略。
只是为了完整,基于此处的另一个答案:
Task.Run(Func<Task>) 会将函数的结果在线程池中排队,当排队的任务完成(包括所有等待)时,结果函数将完成
Task.Run( MethodA ); 会将方法转换为委托并传递。
Task.Run( () => MethodA() ); 将创建一个隐藏方法,该方法将返回MethodA 的结果(该隐藏方法将被转换为委托并传递)。
Task.Run( async () => await MethodA() ); 将创建一个包含 await 的隐藏方法,但如前所述,这将转换为状态机,最终将 MethodA() 的结果包装在新的 Task 中。
Task.Run( () => { MethodA(); } ); 完全不同,因为大括号,这将调用 Task.Run(Action) 重载,在这种情况下,MethodA() 将在此任务上运行,直到它遇到第一个未完成的等待然后完成。这个内部任务完成后(内部等待之后)发生的事情将不会被这个Task.Run 监控,但会继续在线程池上运行,如果它抛出异常,可能会导致您的应用程序崩溃。原因是MethodA返回的任务由于缺少关键字return而被忽略。
Task.Run( () => { return MethodA(); } ); 是针对此异常的修复程序,并且可以像所有其他示例一样工作。