首页 > 解决方案 > Task.Run 中的异步 lambda 与常规 lambda

问题描述

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

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

有什么区别:

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

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

标签: c#task-parallel-library

解决方案


根据 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(); } );是此异常的修复程序,并且将与所有其他示例一样工作。


推荐阅读