深入探究C#的异步编程实现

C#语言中,异步编程是一个重要的特性,它允许程序在执行长时间操作时不会阻塞主线程。虽然异步编程的高级功能已经在Microsoft的官方文档中有详细的介绍,但本文旨在探索其内部实现。如果对异步编程的整体功能还不熟悉,可以首先参考Microsoft的深入文章:。

自从异步编程功能发布以来,一直对其内部实现感到好奇,这促使进行了深入的调查研究,从而撰写了本文。在文章中,可能得出了一些错误的结论,因此欢迎任何形式的反馈(即使是对进行口头攻击:P)。

本文中的大多数结论都是通过长时间观察IL代码并尝试理解其含义得出的。已经包含了IL代码,以便可以双重检查发现。

Async/Await概述

异步功能是由C#编译器与.NET框架基础类库共同实现的。运行时本身不需要修改,尽管完全有可能进行了一些调整以提高async/await的性能。简而言之,这意味着可以使用早期版本的.NET中的一些辅助类自己编写相同的功能,但它不提供向后兼容性。

桩方法

当调用一个async方法时,首先发生的事情是返回其桩。例如,对于以下方法:

public async Task<string> GetStringAsync(string value) { var result = value.ToUpper(); await Task.Delay(1000); return result; }

编译器生成以下代码(如果非常好奇,请查看文章末尾的IL文件):

public Task<string> GetStringAsync(string value) { AsyncClass.<GetStringAsync>d__0 <GetStringAsync>d__; <GetStringAsync>d__.<>4__this = this; <GetStringAsync>d__.value = value; <GetStringAsync>d__.<>t__builder = AsyncTaskMethodBuilder<string>.Create(); <GetStringAsync>d__.<>1__state = -1; AsyncTaskMethodBuilder<string> <>t__builder = <GetStringAsync>d__.<>t__builder; <>t__builder.Start<AsyncClass.<GetStringAsync>d__0>(ref <GetStringAsync>d__); return <GetStringAsync>d__.<>t__builder.Task; }

AsyncTaskMethodBuilder的完整实现可以在这里查看:。在这里,编译器初始化状态机结构的各种变量,所有的魔法都在状态机中实现。结构是一个明显的选择,不想每次调用方法时都在堆上创建一个对象,因为这将显著降低异步方法的性能,为垃圾回收器带来更多工作。

编译器使用不支持的命名约定以确保没有冲突。然而,如果修正变量名,在实际实现方面并没有什么新东西,代码实际上可以在以前的.NET Framework版本中编译,只要自己实现辅助类。

另一个有趣的观察是,async关键字对方法的外部使用方式没有影响。这是不能在接口方法定义中使用async关键字的原因之一,并且允许实现使用以前版本的.NET编写的代码,只要它们返回Task, Task或void。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485