Task.Run中的异步Lambda与常规Lambda

时间:2018-06-30 02:07:32

标签: c# task-parallel-library

假设我有一个方法,该方法使用一些异步调用来运行连续的while循环

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

两者之间有什么区别?

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

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

3 个答案:

答案 0 :(得分:1)

async () => await MethodA();

基本上是async void,并且不会被观察

  

要了解这种效果,我们需要记住async方法   操作。当您调用async方法时,它开始运行   同步地。

     

如果该方法中没有任何await(或者如果所有   方法中的等待项中的已经存在的等待项   在等待时完成)然后该方法将运行   完全同步

     

但是,当方法遇到第一个   await产生,async方法返回。如果是async   返回TaskTask<TResult>的方法,此时的方法   点返回代表ask<TResult>的Task或T async   方法的执行,调用者可以使用该任务等待   同步(例如Wait())或异步(例如await,ContinueWith)   使该方法异步完成。

     

但是,在使用void方法的情况下,不会交出任何句柄。因此,异步void方法   通常被称为“忘了忘了”。

Id建议在async await上浏览许多 Stephen Cleary 信息。这是一个开始

When correctly use Task.Run and when just async-await

Parallel先生的好文章 Stephen Toub

Potential pitfalls to avoid when passing around async lambdas

答案 1 :(得分:0)

根据斯蒂芬·克莱尔(Stephen Cleary)在答案https://stackoverflow.com/a/19098209/3107892中的回答以及他的链接博客文章,唯一的区别是第二个创建了状态机。在这里,您可以使用第一种情况,而没有任何缺点。

以下是您可以遵循的一些准则:

  • 默认情况下不逃避。使用异步并等待自然的,易于阅读的代码;
  • 当方法只是传递或重载时,请考虑隐藏;
  • 如果希望该方法显示在堆栈跟踪中,请不要忽略。

仅此而已,基于此处的另一个答案: Task.Run(Func<Task>)将在线程池中将函数的结果排队,并且当排队的任务完成(包括所有等待)时,结果函数将完成

Task.Run( MethodA );会将方法转换为委托并将其传递。

Task.Run( () => MethodA() );将创建一个隐藏方法,该方法将返回MethodA的结果(此隐藏方法将转换为委托并继续传递)。

Task.Run( async () => await MethodA() );将创建一个包含await的隐藏方法,但是如前所述,该方法将转换为状态机,最后将MethodA()的结果包装到新的{{1 }}。

Task完全不同,由于花括号,这将导致Task.Run(Action)重载,在这种情况下,Task.Run( () => { MethodA(); } );将继续执行此任务,直到遇到第一个未完成的任务等待,然后完成。此内部任务完成之后(内部等待之后)将不会受到此MethodA()的监视,但是将继续在线程池上运行,并且如果引发异常,则可能导致应用程序崩溃。原因是Task.Run返回的任务由于缺少关键字MethodA而被忽略。

return是对此异常的修复,将与所有其他示例一样工作。

答案 2 :(得分:-1)

有很大的不同。 MethodA()返回Task。如果您不等待该Task的结果,那么处理将照常进行。

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

MethodA()一旦在内部达到等待状态,就会返回Task。 lambda现在已完成(它已调用MethodA()并获得了返回值),因此Task.Run()将其自身的任务标记为已完成,并且线程将被释放。

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

lambda是异步的,您正在等待MethodA()的真实结果。由Task返回的Task.Run()在MethodA()完成之前不会完成。