第 17 章 异步语言功能 异步语言功能
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
C# 为使用和实现异步方法提供了语言级支持。异步 API 通常是使用某些服务的最有效方法。例如,大多数 I/O 都是在操作系统内核中异步处理的,因为大多数外设(如磁盘控制器或网络适配器)都能自主完成大部分工作。它们只在每次操作开始和结束时才需要 CPU 参与。
虽然操作系统提供的许多服务本质上都是异步的,但开发人员通常会选择通过同步 API(即工作完成后才返回的 API)来使用它们。这是一种资源浪费,因为它们会阻塞线程,直到 I/O 完成。线程会产生开销,为了获得最佳性能,通常最好使用相对较少的操作系统线程。理想情况下,应用程序的操作系统线程数量与硬件线程数量相同,但只有确保线程只在没有未完成工作时才会阻塞,才能达到最佳效果。(第 16 章介绍了操作系统线程和硬件线程的区别)。在同步 API 调用中阻塞的线程越多,处理工作负载所需的线程就越多,从而降低了效率。在对性能敏感的代码中,异步 API 是非常有用的,因为线程可以在等待 I/O 完成的过程中启动工作,然后做其他有意义的事情,而不是强迫线程坐等 I/O 完成而浪费资源。
异步应用程序接口的问题在于,使用起来可能比同步应用程序接口复杂得多,尤其是当你需要协调多个相关操作并处理错误时。这就是为什么在主流编程语言提供内置支持之前,开发人员通常会选择效率较低的同步替代方案。2012 年,C# 和 VB 将此类功能带出了研究实验室,此后,许多其他流行语言也增加了类似功能(最著名的是 JavaScript,它在 2016 年获得了一种看起来非常相似的语法)。C# 中的异步功能使编写使用高效异步 API 的代码成为可能,同时保留了使用较简单同步 API 的代码的大部分简洁性。
异步功能在某些场景中也很有用,在这些场景中,最大化吞吐量并不是主要的性能目标。在客户端代码中,避免阻塞用户界面线程以保持响应速度非常重要,异步 API 提供了一种实现方法。异步代码的语言支持可以处理线程亲和性问题,从而大大简化了编写高响应性用户界面代码的工作。
异步关键字:async 和 await
C# 通过两个关键字提供对异步代码的支持:async 和await 。其中第一个关键字并不是单独使用的。如果在方法的声明中加入async 关键字,编译器就会知道您打算在方法中使用异步功能。如果没有这个关键字,就不允许使用await 关键字。这可以说是多余的--如果在没有async 的情况下尝试使用await ,编译器会产生错误。如果编译器知道方法的主体试图使用异步特性,为什么还要明确告诉它呢?原因有二。首先,正如你将看到的,这些特性从根本上改变了编译器生成的代码的行为,因此,对于任何阅读代码的人来说,清楚地显示方法的异步行为是非常有用的。其次,await 并不总是 C# 中的一个关键字,因此开发人员曾经可以自由地将其用作标识符。也许微软本可以设计await 的语法,使其仅在非常特定的上下文中充当关键字,从而使您可以在所有其他情况下继续将其用作标识符,但 C# 团队决定采取一种略微粗粒度的方法:您不能在async 方法中将await 用作标识符,但它在其他任何地方都是有效的标识符。
备注
async 关键字不会改变方法的签名。它决定了方法的编译方式,而不是使用方式。
因此,async 关键字只是声明您打算使用await 关键字。(虽然在没有使用async 的情况下不能使用await ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access