什么是异步保证?

时间:2015-10-01 01:23:47

标签: c# async-await

如果方法被标记为异步,是否有任何保证?

如果没有,调用异步方法以确保非阻塞行为的最佳做法是什么? (特别是在调用第三方库时)

更长的版本:

到目前为止,我假设等待异步方法保证不会阻塞线程(如果正确实现)。但是,我最近有this situation(也发生在others)。 在这种情况下,(非)阻塞行为取决于EF提供程序。由于UI层不应该真正了解或关心数据库提供程序实现细节,我认为在Task.Run中包装所有调用以确保非阻塞性行为是有意义的。但是除了UI层之外,我不需要任何异步,这让我质疑一直有异步的哲学。

3 个答案:

答案 0 :(得分:4)

标记方法async实际上没有任何保证,当然也不保证该方法将异步运行。

它做了什么(但我不会称这些保证):

  • 允许在方法中使用await关键字(但 强制执行它!)。
  • 它会强制方法的返回类型为voidTaskTask<TResult>。在最后两种情况下,它使编译器能够为您生成代码,知道如何在Task中设置返回值,或者为您透明地传播未处理的异常。

但是强调: 保证方法将以异步方式编码。你可以自己检查一下。编写一个普通方法,将其标记为async,并“忘记”await方法内的任何内容。您应该从编译器收到关于同步方法的警告,但是将允许它。

我认为你会发现通过Async/Await FAQ来澄清你的一些疑问是有用的:

  

在方法上使用async关键字是否强制该方法的所有调用都是异步的?

     

没有。当您调用标记为async的方法时,它将开始在当前线程上同步运行。因此,如果您有一个返回void的同步方法,并且您要做的就是将其标记为async,那么该方法的调用仍将同步运行。无论您将返回类型保留为void还是将其更改为Task,都是如此。同样,如果您有一个返回一些TResult的同步方法,并且您所做的只是将其标记为async并将返回类型更改为Task<TResult>,则该方法的调用仍将运行同步。

     

将方法标记为“async”不会影响方法是同步还是异步运行。

答案 1 :(得分:2)

  

我认为在Task.Run中包装所有调用以确保非阻塞性行为是有意义的

我不认为这样。虽然您确实无法保证,但大多数 async方法实际上都是异步的。所以我认为只有在你发现一个方法(或它的一些实现)实际上是阻塞的时候才应该在Task.Run()中包装调用,而不是之前。

答案 2 :(得分:1)

  

如果某个方法被标记为异步,那么它是否有任何保证?

不,正如其他人所说,它无法保证实际操作是异步的。它只是提示您理解可能是异步操作。您主要依靠实现这些异步方法的人来实际暴露真正的异步操作,而不是欺骗&#34;假异步&#34;使用Task.Run

例如,此方法返回Task

public Task<string> DoHeavyLiftingAsync()
{
    var tcs = new TaskCompletionSource<string>();
    string result = SomeHeavyWork();
    return tcs.SetResult(result);
}

基本上,没有执行异步操作。这会发生吗?是的,如果执行它的人没有意识到他向来电者提供的保证,可能会发生这种情况。

  

如果没有,调用异步方法的最佳做法是什么   确保无阻塞行为? (特别是在呼叫第三方时   库中?

通常,您可以信任BCL中的异步实现,以便为您提供真正的异步(尽管you may be surprised at times)。如果您正在使用第三方API,则可以始终使用.NET反编译器查看代码,以了解幕后实际发生的情况。如果在执行此操作后,您仍然不确定,则可以始终使用Task.Run打包电话。请确保将其作为最后的手段使用。