一、async、await本质
直接说结论:它们是C#提供的语法糖,编译器编译后是状态机的调用。
先看如下的一段代码,要main方法中调用了三个await方法
将此dll进行反编译为4.0的代码如下:
可见到两个Main方法,也就是说我们在程序中Main方法上加了async关键词,编译器会编译成一个是异步的一个是非异步方法,程序还是将非异步的方法作为入口函数。进入函数
在该函数中调了异步的Main方法,再进入:
在该函数中创建了一个状态机,将参数传给状态机,并调用期Start方法,可知异步方法实际上是状态机方法的调用
进入状态机类型
private sealed classd__0 : IAsyncStateMachine { public int 1__state; public AsyncTaskMethodBuilder t__builder; public string[] args; private string 5__1; private HttpClient 5__2; private string 5__3; private 服务器托管网string s__4; private string s__5; private TaskAwaiterstring> u__1; private TaskAwaiter u__2; private void MoveNext() { int num = 1__state; try { TaskAwaiter awaiter2; TaskAwaiterstring> awaiter; switch (num) { default: 5__2 = new HttpClient(); goto case 0; case 0: try { TaskAwaiterstring> awaiter3; if (num != 0) { awaiter3 = 5__2.GetStringAsync("https://www.baidu.com").GetAwaiter(); if (!awaiter3.IsCompleted) { num = (1__state = 0); u__1 = awaiter3; d__0 stateMachine = this; t__builder.AwaitUnsafeOnCompleted(ref awaiter3, ref stateMachine); return; } } else { awaiter3 = u__1; u__1 = default(TaskAwaiterstring>); num = (1__state = -1); } s__4 = awaiter3.GetResult(); 5__3 = s__4; s__4 = null; Console.WriteLine(5__3); 5__3 = null; } finally { if (num 0 && 5__2 != null) { ((IDisposable)5__2).Dispose(); } } 5__2 = null; awaiter2 = File.WriteAllTextAsync("E:test.txt", "zhengwei").GetAwaiter(); if (!awaiter2.IsCompleted) { num = (1__state = 1); u__2 = awaiter2; d__0 stateMachine = this; t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine); return; } goto IL_015f; case 1: awaiter2 = u__2; u__2 = default(TaskAwaiter); num = (1__state = -1); goto IL_015f; case 2: { awaiter = u__1; u__1 = default(TaskAwaiterstring>); num = (1__state = -1); break; } IL_015f: awaiter2.GetResult(); Console.WriteLine("写入成功"); awaiter = File.ReadAllTextAsync("E:test.txt").GetAwaiter(); if (!awaiter.IsCompleted) { num = (1__state = 2); u__1 = awaiter; d__0 stateMachine = this; t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); return; } break; } s__5 = awaiter.GetResult(); 5__1 = s__5; s__5 = null; Console.WriteLine("文件内容" + 5__1); } catch (Exception exception) { 1__state = -2; 5__1 = null; t__builder.SetException(exception); return; } 1__state = -2; 5__1 = null; t__builder.SetResult(); } void IAsyncStateMachine.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext this.MoveNext(); } [DebuggerHidden] private void SetStateMachine(IAsyncStateMachine stateMachine) { } void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) { //ILSpy generated this explicit interface implementation from .override direc服务器托管网tive in SetStateMachine this.SetStateMachine(stateMachine); } }
在此状态机类中可以看到我们自己写的Main方法中的主要代码已编译到了方法MoveNext()中,并将我们的局部变量编译成了成员变量
方法中有一个case,我们自己写的三个异步方法被编译后拆到了多个case中去了,MoveNext方法会根据不同的num被多次调用
编译的代码中可见到在每次调用异步方法时都会去判断是否完成
编译后的代码意思是当执行到string html = await httpClient.GetStringAsync(“https://www.baidu.com”);时,如果没有完成就直接返回了,并不会再往下执行
只有当此段代码执行完成后会继续往下执行,当执行到第二个异步方法await File.WriteAllTextAsync(@”E:test.txt”,”zhengwei”)时又会返回,等待执行完后再往下执行
同理,执行第三步异步方法var text = await File.ReadAllTextAsync(@”E:test.txt”);也是如此
所有异步方法都执行完成后,会break;跳出状态机。
未完待续。。。
二、async背后的线程切换
三、异步方法与多线程的关系
四、CancellationToken在异步方法中的使用
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 从科幻走向现实,LLM Agent 做到哪一步了?
高春辉、王春生、朱峰:关于开源创业的15件小事 LLM 洪流滚滚,AI 浪潮席卷全球,在这不断冲击行业认知的一年中,Agent 以冉冉新星之态引起开发者侧目。OpenAI 科学家 Andrej Karpathy 曾言“OpenAI 在大模型领域快人一步,但在 …