【问题标题】: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(); } ); 是针对此异常的修复程序,并且可以像所有其他示例一样工作。

    【讨论】:

      猜你喜欢
      • 2017-12-19
      • 1970-01-01
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      • 2022-11-30
      • 2017-01-06
      • 1970-01-01
      相关资源
      最近更新 更多