.net 中异步async await

基本原理

async ,await是C#语言中用于简化异步操作的语法糖,实际会由编译器将代码翻译生成状态机
执行异步操作。
状态机 是一种数学模型,用于描述一个系统在不同状态之间的转换行为。它由一组状态和一组转换组成,在特定的输入条件下,系统从一个状态转换到另一个状态。
例如如下的异步方法

public async Task<string> FetchDataAsync(string url)  
{  
	using (HttpClient client = new HttpClient())  
	{  
		string content = await client.GetStringAsync(url);
		Console.WriteLine("执行成功!");
		return content;  
	}  
}

当编译器遇到Async符号时,会将整个方法,转换为状态机,反编译整理简化后相关代码如下:

public Task<string> FetchDataAsync(string url)  
{  
	var stateMachine = new FetchDataStateMachine();  
	stateMachine.url = url;  
	stateMachine.builder = AsyncTaskMethodBuilder<string>.Create();  
	stateMachine.state = -1;  
	stateMachine.builder.Start(ref stateMachine);  
	return stateMachine.builder.Task;  
}  
  
private struct FetchDataStateMachine : IAsyncStateMachine  
{  
	public int state;  
	public AsyncTaskMethodBuilder<string> builder;  
	public string url;  
	private HttpClient client;  
	private TaskAwaiter<string> awaiter;  
	private string result;  
  
	public void MoveNext()  
	{  
		try  
		{  
			if (state!=0)  
			{  
				client = new HttpClient();  
				var task = client.GetStringAsync(url);  
				awaiter = task.GetAwaiter();  
				//判断任务是否已经执行完毕,如果执行完,直接就返回结果了
				if (!awaiter.IsCompleted)  
				{  
					state = 0;
					//注册回调,当task执行完后再执行MoveNext方法
					builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);  
					return;  
				}  
			}  
			//任务执行完毕后设置state
			if (state == 0)  
			{  
				state = -1;   
			}  
  		    result = awaiter.GetResult();  
  		    //执行await 以后的代码
  		    Console.WriteLine("执行成功!"); 
		}  
		catch (Exception ex)  
		{  
			state = -2;  
			builder.SetException(ex);  
		}  
		finally
		{
			if(num<0&&client!=null)
			{
				client.Dispose();
			}
		}
		state=-2;
		builder.SetResult(result);  
	}  
  
	public void SetStateMachine(IAsyncStateMachine stateMachine)  
	{  
		builder.SetStateMachine(stateMachine);  
	}  
}

编译器会生成一个FetchDataStateMachine 状态机类, 继承自IAsyncStateMachine 接口,将异步方法中的相关变量放在状态机字段中;状态机中的一个重要方法是MoveNext(),用于处理状态变化时的对应操作。
翻译后的代码主要执行以下两个操作

  • 初始化状态机 , 新增状态机,并初始化相关字段,设置初始状态state为-1,启动状态机。
  • 执行MoveNext()方法,state!=0,执行任务,如果任务耗时短直接可以获取结果,则直接返回结果;耗时长则设置state字段为0,并通过AwaitUnsafeOnCompleted注册任务完成后的回调,当任务完成后会再执行MoveNext()方法,此时state 字段为0,方法从awaiter中获取执行结果,并执行原方法中await以后的后续代码并返回。
    AsyncTaskMethodBuilder<T>中AwaitUnsafeOnCompleted方法
   internal static void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref Task<TResult>? taskField)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            IAsyncStateMachineBox box = GetStateMachineBox(ref stateMachine, ref taskField);
            AwaitUnsafeOnCompleted(ref awaiter, box);
        }



   internal static void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref Task<TResult>? taskField)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            IAsyncStateMachineBox box = GetStateMachineBox(ref stateMachine, ref taskField);
            AwaitUnsafeOnCompleted(ref awaiter, box);
        }




        internal static void AwaitUnsafeOnCompleted<TAwaiter>(
            ref TAwaiter awaiter, IAsyncStateMachineBox box)
            where TAwaiter : ICriticalNotifyCompletion
        {
            if ((null != (object?)default(TAwaiter)) && (awaiter is ITaskAwaiter))
            {
                ref TaskAwaiter ta = ref Unsafe.As<TAwaiter, TaskAwaiter>(ref awaiter); // relies on TaskAwaiter/TaskAwaiter<T> having the same layout
                TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, continueOnCapturedContext: true);
            }
            else if ((null != (object?)default(TAwaiter)) && (awaiter is IConfiguredTaskAwaiter))
            {
                ref ConfiguredTaskAwaitable.ConfiguredTaskAwaiter ta = ref Unsafe.As<TAwaiter, ConfiguredTaskAwaitable.ConfiguredTaskAwaiter>(ref awaiter);
                TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, (ta.m_options & ConfigureAwaitOptions.ContinueOnCapturedContext) != 0);
            }
            else if ((null != (object?)default(TAwaiter)) && (awaiter is IStateMachineBoxAwareAwaiter))
            {
                try
                {
		        ((IStateMachineBoxAwareAwaiter)awaiter).AwaitUnsafeOnCompleted(box);
                }
                catch (Exception e)
                {
                    Threading.Tasks.Task.ThrowAsync(e, targetContext: null);
                }
            }
            else
            {
                // The awaiter isn't specially known. Fall back to doing a normal await.
                try
                {
                    awaiter.UnsafeOnCompleted(box.MoveNextAction);
                }
                catch (Exception e)
                {
                    Threading.Tasks.Task.ThrowAsync(e, targetContext: null);
                }
            }
        }

AwaitUnsafeOnCompleted()方法根据awaiter 的类型注册对应的OnCompleted任务完成后的回调方法,也就是MoveNext()方法,其中状态机被封装在IAsyncStateMachineBox类型的box中。
整个状态机的执行流程如下图

参考内容

Async/Await deep dive: how dotnet manage asynchronous code
Async/Await在 C#语言中是如何工作的
深入理解async 和 await 理解
.NET 6.0 中的 await 原理浅析
async、await原理揭秘
NetCore高级系列文章04---async、await原理揭秘
.NET Task 揭秘(3)async 与 AsyncMethodBuilder - 黑洞视界 - 博客园
进阶篇:以IL为剑,直指async/await - Dev_Eric - 博客园

posted @   岛dao  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示