新库中的异步与非异步方法

时间:2014-09-22 06:43:35

标签: c# asynchronous async-await task

在.NET 4.5中,现在有很多方法可以用于异步和非异步对,例如Flush()FlushAsync()。理想情况下,I / O交互在可能的情况下始终是异步的(如果您确实需要,可以始终使用.Wait()阻止),但非同步(阻塞)版本显然需要保留,因为向后兼容。

在推出一个没有向后兼容性限制的全新库时,是否有任何理由可以包含非异步方法?

4 个答案:

答案 0 :(得分:7)

异步方法通常会有与之相关的成本,因为编译器生成了一个状态机,这导致了相当多的额外代码。如果您没有使用async方法,那么他们将无法进行评估,因此您可以避免这笔费用。

如果您使用async版本而只是致电Wait(),那么您将面临deadlock的风险,并且在async操作完成后您还需要进行额外的上下文切换。总的来说,结果会稍差一些。

此外,您获得的任何异常现在都将包含在AggregatedException中,因此在异常处理中也会有额外的工作。看看Async Performance: Understanding the Costs of Async and Await

答案 1 :(得分:4)

Ned的答案非常好,所以我不会重复他所说的内容(尽管请注意,与I / O操作本身的成本相比,开销并不一定很大。)

提供同步方法的另一个重要原因实际上很明显 - 人们在理解异步操作时遇到了很多麻烦。他们习惯于做“读,然后写,然后再读......”错误处理,错误局部性,同步......所有这些都很容易变得非常棘手,特别是如果你不能使用await

事实是,如果一切都随着时间的推移变得异步将是非常好的,那么推理异步应用程序要困难得多。它仍然比做多线程更好,但不是很多。

通过这种方式,使用异步方法可以被视为一种优化 - 除非您知道它们将显着提供帮助,否则不会进行优化。对于图书馆来说,这很难决定 - 所以提供两种选择。编写高吞吐量服务器的人将需要谨慎编写高性能且可靠的异步应用程序。例如,有人只是编写一个简单的CMS,可能希望完全避免它。

这尤其适用于4.5以下的C#/ .NET - 尝试在没有await的情况下对异步延续进行错误处理,你会看到我在说什么:)

保持代码简单非常重要。它大大降低了开发和维护成本,并使新手更容易理解。

答案 2 :(得分:4)

async和同步版本之间存在轻微的差异(大多数可以忽略不计),但我会说没有理由让两个版本具有相同的操作。您应该在库的实施过程中决定哪个版本最合适。自然异步操作(例如下载文件)应该是async,并且CPU绑定操作应该是同步的。

您可以看到WinRT框架中使用的范例:

  

为了实现这些目标,我们在Windows运行时中使许多可能与I / O绑定的API异步。如果同步写入(例如,可能需要花费超过50毫秒的时间来执行),这些是最可能明显降低性能的候选者。这种API的异步方法使您能够编写默认情况下快速且流畅的代码,并提升应用程序响应在Metro风格应用程序开发中的重要性。

来自Keeping apps fast and fluid with asynchrony in the Windows Runtime

曾经是这样的情况,使用异步重载比同步重载更加困难和复杂,因此拥有两个版本是一个好主意。 async-await不再是这种情况。

答案 3 :(得分:0)

唯一的原因是您希望支持应用程序以4.5之前的.NET Framework为目标。如果您有这样的应用程序并且想要使用新库,那么您将被迫使用非异步方式。

您也可以使用Async Targeting Package.使用.NET 4.0编译新程序集。这样做我建议你创建两个项目:一个是4.5,一个是4.0。