Task.Run 中的异步 lambda 与常规 lambda [重复]

Posted

技术标签:

【中文标题】Task.Run 中的异步 lambda 与常规 lambda [重复]【英文标题】:Async lambda vs regular lambda in Task.Run [duplicate] 【发布时间】:2018-12-09 04:56:25 【问题描述】:

假设我有一个方法可以运行带有一些异步调用的连续 while 循环

async Task MethodA()
    while(true) perform async/await operations 

有什么区别:

Task.Run( () => MethodA(); 
Task.Run( async () => await MethodA(); 

如果有区别,什么时候比另一个更有用?

【问题讨论】:

这能回答你的问题吗? What is the purpose of "return await" in C#? 【参考方案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://***.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(); ); 是针对此异常的修复程序,并且可以像所有其他示例一样工作。

【讨论】:

以上是关于Task.Run 中的异步 lambda 与常规 lambda [重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何对带有异步的流进行单元测试

Task.Run() 代码是不是异步执行?

Parallel.ForEach 与 Task.Run 和 Task.WhenAll

将异步委托传递给Task.Run? [复制]

Task.Run()方法总结

task 异步