如果方法被标记为异步,是否有任何保证?
如果没有,调用异步方法以确保非阻塞行为的最佳做法是什么? (特别是在调用第三方库时)
更长的版本:
到目前为止,我假设等待异步方法保证不会阻塞线程(如果正确实现)。但是,我最近有this situation(也发生在others)。 在这种情况下,(非)阻塞行为取决于EF提供程序。由于UI层不应该真正了解或关心数据库提供程序实现细节,我认为在Task.Run中包装所有调用以确保非阻塞性行为是有意义的。但是除了UI层之外,我不需要任何异步,这让我质疑一直有异步的哲学。
答案 0 :(得分:4)
标记方法async
实际上没有任何保证,当然也不保证该方法将异步运行。
它做了什么(但我不会称这些保证):
await
关键字(但 不 强制执行它!)。void
,Task
或Task<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
打包电话。请确保将其作为最后的手段使用。