写点什么

使用 Async 和 Await 的代价

  • 2011-10-13
  • 本文字数:2007 字

    阅读完需:约 7 分钟

异步技术能使得应用程序的总吞吐量得到显著提升,但这并不是无偿的。异步函数往往比其同步替代方案稍慢一些,而且如果您不介意采用它还会增加相当大的内存压力的话。Stephen Toub 最近在 MSDN 杂志中一篇题为“异步性能:了解 Async 和 Await 的代价”的文章中讨论了该主题。

相对于本机 C++ 代码而言,托管代码最显著的优势之一就是运行时内联函数(inline function)[1] 的能力。CLR 的 JIT 编译器甚至可以跨程序集内联函数,从而大大降低了调用细粒度方法(OOP 程序员偏爱此类方法)的开销。不幸的是,异步调用的本质意味着不能内联委托(delegates cannot be inlined)。此外,在建立异步调用时还包括不少样板代码。因此,这导致了 Stephen 的第一条建议,“考虑粗粒度,而非细粒度(Think Chunky, Not Chatty)”[2]。就像你正在穿越某个 COM 或 p/invoke 边界一样,相对于许多的小型异步调用而言,你应该会更喜爱少数的大型异步调用。

异步模式下无需开发者显式使用 new 运算符,即可通过多种方式分配内存。如果任其发展,这些内存分配法可能导致过大的内存压力,并且由于垃圾回收器尝试跟进还会导致不必要的延迟。考虑来自 Stream 子类的这个签名及其返回语句:

复制代码
public override async Task<int> ReadAsync()<br></br>return this.Read()

此处没有展示隐式创建 Task 对象,该对象用于包装从 Read 方法中返回的整型值。在 Stephen 的文章中,他展示了如何通过缓存最近的 Task对象及重用该对象来降低内存开销。

导致意外对象分配和保留的另一原因是使用闭包(closures)。C#和 VB 中的闭包是通过匿名类来实现的,匿名类包含匿名方法,而且在方法中声明了异步函数。那些匿名函数所需的本地变量据说被“封闭”(closed over)或“提升” (lifted)到该匿名类中。当每次调用匿名类的父方法时都必须创建一个该类实例。

问题并未就此结束,仍有可能使得额外的内存分配进一步恶化。通常情况下,局部变量所引用的对象是被热切请求的,垃圾回收器(GC)一旦明确那些局部变量在当前函数中将不再被使用时就会回收它们。由于在异步函数中所使用的“局部变量”实际上是某个匿名类中的字段,因此在调用期间它们必须被保留。如果此过程耗时数秒,这对于异步调用而言是很常见的,而该匿名类可能在不经意间被晋升为垃圾回收器中更昂贵的 1 代或 2 代对象 [3]。如果这成为问题,Stephen 建议一旦不再需要那些局部变量就应显式地把它们设置为空引用。

Stephen 所讨论的第三个问题是上下文的概念,特别是同步上下文(synchronization context)和执行上下文(execution context)。他在文章中展示了库代码如何通过使用ConfigureAwait 方法故意忽略同步上下文、以及避免某些必须在执行上下文中捕获的事情来获得性能提升的办法。

译注

[1] 内联函数(inline function),在不同的编程语言中,内联函数(inline function)是指已要求编辑器对其执行内联展开( inline expansion )的函数。换言之,程序员已要求编译器将每处调用某函数的地方都插入完整的函数体,而不是生成代码以便从其定义的地方调用该函数。可以使用 C99 或 C++ 编写内联函数,例如:

复制代码
inline int max(int a, int b)
{
return (a > b) ? a : b;
}

然后,调用语句如下:

复制代码
a = max(x, y);

该语句在编译后,可能被转换成为更直接的计算:

复制代码
a = (x > y) ? x : y;

详见 Inline function

[2] 考虑粗粒度,而非细粒度(Think Chunky, Not Chatty),Chunky 与 Chatty 之争此前多见于“服务协定设计”(service contract design)。唠叨的服务(Chatty Service)趋向于返回简化信息,并使用更细粒度的操作。矮胖的服务(Chunky Service)趋向于返回复杂层次信息,并使用粗粒度的操作。换言之,二者不同之处在于,当返回同样的信息时,唠叨的服务与矮胖的服务相比则需要更多的调用,却增加了返回实际需要的适当信息的灵活性。详见 WCF service contract design

[3] 1 代或 2 代对象,“代”是垃圾回收器用到的概念。提到垃圾回收器就不得不说“托管堆的简化模型”,该模型的规则如下:

  • 所有可进行垃圾回收的对象都分配在一个连续的地址空间范围(托管堆)内。
  • 堆被划分为代 (generation),以便只需查找堆的一小部分就能清除大多数垃圾。
  • 代中的对象大体上均为同龄。
  • 代的编号越高,表示堆的这一片区域所包含的对象越老——这些对象就越有可能是稳定的。最老的对象位于最低的地址内,而新的对象则创建在增加的地址内。
  • 新对象的分配指针标记了内存的已使用(已分配)内存区域和未使用(可用)内存区域之间的边界。
  • 通过删除死对象并将活对象转移到堆的低地址末尾,堆周期性地进行压缩。这就扩展了在创建新对象的图表底部的未使用区域。
  • 对象在内存中的顺序仍然是创建它们的顺序,以便于定位。
  • 在堆中,对象之间永远不会有任何空隙。
  • 只有某些可用空间是已提交的。需要时,操作系统会从“保留的”地址范围中分配更多的内存。

详见“垃圾回收器基础与性能提示”

查看英文原文: The Cost of Async and Await

2011-10-13 04:216456
用户头像

发布了 55 篇内容, 共 18.1 次阅读, 收获喜欢 0 次。

关注

评论

发布
暂无评论
发现更多内容

小程序开发技术解析:事件系统设计

Onegun

小程序 事件 小程序开发

打通数据治理全链路,火山引擎DataLeap数据治理平台公有云版本正式发布

字节跳动数据平台

大数据 数据中台 数据研发 企业号 8 月 PK 榜

人工智能如何应对 DevOps 监控和可观测性挑战

SEAL安全

人工智能 DevOps 运维

低代码平台什么意思

优秀

低代码平台

金蝶管易云 X Hologres:新一代全渠道电商ERP最佳实践

阿里云大数据AI技术

ERP

柴洪峰院士:大模型赋能金融科技思考与展望

NLP资深玩家

人工智能 金融科技 大模型 WAIC

加速数字化转型:龙智专家分享DevSecOps和ITSM工具性能优化策略——2023 DevOps国际峰会现场访谈

龙智—DevSecOps解决方案

DevSecOps devops国际峰会

SpringCloud Gateway 在微服务架构下的最佳实践

阿里巴巴云原生

阿里云 云原生 Spring Cloud Gateway

javascript数组基础

timerring

JavaScript

时序数据库 TDengine 被帆软纳入数据源,可视化方案多样化

爱倒腾的程序员

数据库

不用再写FlinkSQL了,使用开源XL-LightHouse轻松实现海量数据实时统计

feng

大数据 流式计算 流式大数据统计 流式统计 企业数据化运营

小白也能基于OpenAI搭建自己的英语学习工具

派大星

openai

智慧消防大数据监控系统 城市火警智能监测

2D3D前端可视化开发

智慧城市 智慧消防 消防物联网云平台 消防云控平台

软件测试 | 什么时候使用表锁

测吧(北京)科技有限公司

软件测试 | 影响MySQL性能的重要参数

测吧(北京)科技有限公司

测试

软件测试 | table_cache的设置

测吧(北京)科技有限公司

测试

云原生大数据平台CloudEon V1.1.0版本发布!

CloudEon开源

大数据 云原生 容器化

C++异步编程开源项目Workflow三岁啦 \^0^/

1412

开源项目 异步编程 异步任务编程 workflow C++

静态分析全解析:助力高质量软件开发,降低成本风险

龙智—DevSecOps解决方案

静态分析 静态代码分析 静态代码分析工具

软件测试 | 源码包安装的性能考虑

测吧(北京)科技有限公司

测试

华为云低代码平台Astro Canvas 搭建汽车展示大屏——实验指导手册

华为云PaaS服务小智

软件开发 低代码 数据可视化 华为云

【Linux工具】yum和gdb详细使用教程。

百度搜索:蓝易云

云计算 Linux 运维 yum 云服务器

MySQL5.7和MySQL8.0的区别是什么?

百度搜索:蓝易云

云计算 Linux 运维 MySQL 5.7 MySQL 8.0

在 Amazon DocumentDB 里处理 Decimal128类型数据的解决方案

亚马逊云科技 (Amazon Web Services)

在Go中使用Arm的SIMD指令

geange

Go 汇编 neon arm64

ShareSDK 国外平台登陆返回参数

MobTech袤博科技

前端 App

软件测试 | 升级MySQL

测吧(北京)科技有限公司

测试

PoseiSwap:通过 RWA 的全新叙事,反哺 Nautilus Chain 生态

威廉META

PoseiSwap:通过 RWA 的全新叙事,反哺 Nautilus Chain 生态

鳄鱼视界

Requests+Etree+BeautifulSoup+Pandas+Path+Pyinstaller应用 | 获取页面指定区域数据存入html、excel文档

Python pandas pyinstaller requests BeautifulSoup

​加速大规模团队创新,开发安全、可靠、合规的汽车软件

龙智—DevSecOps解决方案

ACT汽车电子与软件技术周 汽车电子与软件技术周

使用Async和Await的代价_.NET_Jonathan Allen_InfoQ精选文章