0

0

c# async 状态机生成的代码结构和性能开销分析

煙雲

煙雲

发布时间:2026-01-04 11:11:25

|

627人浏览过

|

来源于php中文网

原创

C# async方法编译后生成继承IAsyncStateMachine的状态机类,包含字段存储局部变量、参数、awaiter和state,并通过MoveNext()中switch(state)调度await前后逻辑,所有局部变量被提升为字段,await转为GetAwaiter/IsCompleted/OnCompleted,异常存于exception字段并在GetResult抛出,每次调用通常分配堆对象导致GC压力。

c# async 状态机生成的代码结构和性能开销分析

async 方法编译后生成的状态机长什么样

你写的 async Task 方法,C# 编译器(Roslyn)不会直接执行它,而是重写为一个状态机类,继承自 IAsyncStateMachine。这个类包含字段:保存局部变量、参数、awaiter、当前 state,以及一个 MoveNext() 方法驱动状态流转。

关键点在于:所有 await 之前的代码、每个 await 之后的“延续”逻辑,都被拆成不同 state 分支,由 switch (state) 调度。局部变量(包括 this、参数、中间结果)全部被提升(lifted)为状态机字段,以保证跨 await 暂停后仍可访问。

  • await 表达式本身被替换为 GetAwaiter() + IsCompleted 判断 + OnCompleted() 注册回调
  • 如果 awaiter 的 IsCompleted == true(如已完成的 Task.FromResult),则跳过挂起,直接执行后续逻辑(同步完成路径)
  • 未捕获异常会被存入状态机的 exception 字段,最终在 GetResult() 中重新抛出

状态机对象分配带来的堆压力

每次调用 async 方法,除非满足极严格的「热路径优化」条件(如 .NET 6+ 中的 ValueTask + 无捕获 + 同步完成),否则都会 new 一个状态机实例 —— 这是托管堆上的对象分配,触发 GC 压力。

尤其高频调用场景(如 Web API 每请求一个 async action、高吞吐消息处理循环),状态机分配会显著抬高 Gen0 GC 频率。

  • 普通 Task-returning async 方法 → 总是分配状态机 + 可能分配 Task 对象(如异步完成时)
  • 改用 ValueTask 可避免 Task 分配,但状态机本身仍会分配(除非方法同步完成且无捕获)
  • 使用 [AsyncMethodBuilder(typeof(ConfiguredValueTaskBuilder))] 等自定义 builder 是高级优化手段,日常慎用

同步完成路径与 await 分支的性能差异

async 方法不是“一定慢”,它的开销集中在「需要挂起并恢复」的分支。如果 await 的操作几乎总是同步完成(例如缓存命中、内存计算、短路逻辑),那大部分调用走的是同步路径,性能接近普通方法 —— 但仍有少量额外字段访问和 switch 开销。

网奇.NET网络商城系统
网奇.NET网络商城系统

系统优势: 1、 使用全新ASP.Net+c#和三层结构开发. 2、 可生成各类静态页面(html,htm,shtm,shtml和.aspx) 3、 管理后台风格模板自由选择,界面精美 4、 风格模板每月更新多套,还可按需定制 5、 独具的缓存技术加快网页浏览速度 6、 智能销售统计,图表分析 7、 集成国内各大统计系统 8、 多国语言支持,内置简体繁体和英语 9、 UTF-8编码,可使用于全球

下载

一旦进入异步分支(比如真正发起 HTTP 请求、磁盘读取),状态机需注册回调、上下文捕获(SynchronizationContext / TaskScheduler)、线程切换,延迟和内存成本明显上升。

  • 默认情况下,await 会尝试捕获当前 SynchronizationContext(如 ASP.NET Core 早期版本),带来额外委托分配;.NET Core 3.0+ 默认禁用,大幅降低开销
  • await task.ConfigureAwait(false) 可显式禁止上下文捕获,适用于类库或后台任务,减少委托和调度开销
  • 过度细粒度的 await(如循环内每轮都 await 一个微小操作)会放大状态机调度成本,应合并或改用同步批量处理

如何观测真实状态机行为

别只看源码 —— 编译后的 IL 和 JIT 汇编才是真相。可用以下方式验证实际行为:

  • SharpLab 查看 C# → IL → 反编译回 C# 的状态机结构
  • dotnet trace + Microsoft-DotNETCore-EventSources 采集 Microsoft-Windows-DotNETRuntime/ThreadPool/WorkerThread/Start 等事件,观察线程切换频率
  • PerfView 分析 GC 分配热点,确认 d__X 类型是否高频出现在 Gen0 分配
public async Task GetCountAsync()
{
    var data = await LoadDataAsync(); // ← 这行触发状态机拆分
    return data.Length;
}

上面这段代码,只要 LoadDataAsync() 返回未完成的 Task,就一定会构造状态机对象,并在 await 完成后通过回调驱动继续执行 return data.Length。这个过程看似透明,但每一步都有明确的内存和调度代价。

真正影响性能的往往不是「用了 async」,而是「在不该挂起的地方挂起了」,或者「挂起后没做上下文优化」。状态机本身是机制,不是瓶颈;滥用才是问题根源。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
switch语句用法
switch语句用法

switch语句用法:1、Switch语句只能用于整数类型,枚举类型和String类型,不能用于浮点数类型和布尔类型;2、每个case语句后面必须跟着一个break语句,以防止执行其他case的代码块,没有break语句,将会继续执行下一个case的代码块;3、可以在一个case语句中匹配多个值,使用逗号分隔;4、Switch语句中的default代码块是可选的等等。

523

2023.09.21

Java switch的用法
Java switch的用法

Java中的switch语句用于根据不同的条件执行不同的代码块。想了解更多switch的相关内容,可以阅读本专题下面的文章。

404

2024.03.13

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

314

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

524

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

49

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

191

2025.08.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

378

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

566

2023.08.10

从零到实战:Python 编程系统入门专题
从零到实战:Python 编程系统入门专题

本专题面向零编程基础及初学者,系统讲解 Python 编程语言的核心知识与实战技巧。内容涵盖 Python 基础语法、数据结构、函数与模块、常用标准库、简单算法思维,以及真实应用场景下的小项目实战。通过循序渐进的学习路径,帮助读者快速建立编程思维,掌握 Python 在数据处理、自动化脚本及日常开发中的实际应用能力,为后续深入学习 Web 开发、数据分析或人工智能打下坚实基础。

2

2026.01.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.6万人学习

Excel 教程
Excel 教程

共162课时 | 10.7万人学习

PHP基础入门课程
PHP基础入门课程

共33课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号