Understanding C# async / await 第1章
Table of Contents
Understanding C# async / await 第1章原文地址
Understanding C# async / await 第2章原文地址
Understanding C# async / await 第3章原文地址
以下是基于你提供的内容的总结和解读,保留示例代码和关键细节:
理解 C# 的 async / await (1):编译过程
1. 概述
C# 的 async
和 await
关键字为异步编程提供了极大的便利。本文将深入探讨这些语法糖背后的实际代码实现。
2. 准备工作
首先,定义一些辅助方法:
internal class HelperMethods
{
private static void IO()
{
using (WebClient client = new WebClient())
{
Enumerable.Repeat("http://weblogs.asp.net/dixin", 10).Select(client.DownloadString).ToArray();
}
}
internal static int Method(int arg0, int arg1)
{
int result = arg0 + arg1;
IO(); // 模拟长时间运行的 IO 操作
return result;
}
internal static Task<int> MethodTask(int arg0, int arg1)
{
Task<int> task = new Task<int>(() => Method(arg0, arg1));
task.Start(); // 返回已启动的任务
return task;
}
internal static void Before() { }
internal static void Continuation1(int arg) { }
internal static void Continuation2(int arg) { }
}
Method()
是一个模拟长时间 IO 操作的方法,MethodTask()
将其包装为 Task
并返回。
3. 使用 async / await
定义一个异步方法 MethodAsync()
,并在其中使用 await
:
internal class AsyncMethods
{
internal static async Task<int> MethodAsync(int arg0, int arg1)
{
int result = await HelperMethods.MethodTask(arg0, arg1);
return result;
}
}
await
关键字用于等待 MethodTask()
返回的 Task
。
4. 编译后的代码
编译后,MethodAsync()
的代码会被转换为以下形式:
internal class CompiledAsyncMethods
{
[DebuggerStepThrough]
[AsyncStateMachine(typeof(MethodAsyncStateMachine))] // async
internal static /*async*/ Task<int> MethodAsync(int arg0, int arg1)
{
MethodAsyncStateMachine methodAsyncStateMachine = new MethodAsyncStateMachine()
{
Arg0 = arg0,
Arg1 = arg1,
Builder = AsyncTaskMethodBuilder<int>.Create(),
State = -1
};
methodAsyncStateMachine.Builder.Start(ref methodAsyncStateMachine);
return methodAsyncStateMachine.Builder.Task;
}
}
async
关键字被移除,实际逻辑被转移到一个状态机 MethodAsyncStateMachine
中:
[CompilerGenerated]
[StructLayout(LayoutKind.Auto)]
internal struct MethodAsyncStateMachine : IAsyncStateMachine
{
public int State;
public AsyncTaskMethodBuilder<int> Builder;
public int Arg0;
public int Arg1;
public int Result;
private TaskAwaiter<int> awaitor;
void IAsyncStateMachine.MoveNext()
{
try
{
if (this.State != 0)
{
this.awaitor = HelperMethods.MethodTask(this.Arg0, this.Arg1).GetAwaiter();
if (!this.awaitor.IsCompleted)
{
this.State = 0;
this.Builder.AwaitUnsafeOnCompleted(ref this.awaitor, ref this);
return;
}
}
else
{
this.State = -1;
}
this.Result = this.awaitor.GetResult();
}
catch (Exception exception)
{
this.State = -2;
this.Builder.SetException(exception);
return;
}
this.State = -2;
this.Builder.SetResult(this.Result);
}
[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0)
{
this.Builder.SetStateMachine(param0);
}
}
状态机的 MoveNext()
方法包含了实际的异步逻辑。
5. 多 await 方法
定义一个更复杂的异步方法 MultiCallMethodAsync()
,包含多个 await
和 continuation 代码:
internal class AsyncMethods
{
internal static async Task<int> MultiCallMethodAsync(int arg0, int arg1, int arg2, int arg3)
{
HelperMethods.Before();
int resultOfAwait1 = await MethodAsync(arg0, arg1);
HelperMethods.Continuation1(resultOfAwait1);
int resultOfAwait2 = await MethodAsync(arg2, arg3);
HelperMethods.Continuation2(resultOfAwait2);
int resultToReturn = resultOfAwait1 + resultOfAwait2;
return resultToReturn;
}
}
编译后,MultiCallMethodAsync()
也会被转换为状态机 MultiCallMethodAsyncStateMachine
:
[CompilerGenerated]
[StructLayout(LayoutKind.Auto)]
internal struct MultiCallMethodAsyncStateMachine : IAsyncStateMachine
{
public int State;
public AsyncTaskMethodBuilder<int> Builder;
public int Arg0;
public int Arg1;
public int Arg2;
public int Arg3;
public int ResultOfAwait1;
public int ResultOfAwait2;
public int ResultToReturn;
private TaskAwaiter<int> awaiter;
void IAsyncStateMachine.MoveNext()
{
try
{
switch (this.State)
{
case -1:
HelperMethods.Before();
this.awaiter = AsyncMethods.MethodAsync(this.Arg0, this.Arg1).GetAwaiter();
if (!this.awaiter.IsCompleted)
{
this.State = 0;
this.Builder.AwaitUnsafeOnCompleted(ref this.awaiter, ref this);
}
break;
case 0:
this.ResultOfAwait1 = this.awaiter.GetResult();
HelperMethods.Continuation1(this.ResultOfAwait1);
this.awaiter = AsyncMethods.MethodAsync(this.Arg2, this.Arg3).GetAwaiter();
if (!this.awaiter.IsCompleted)
{
this.State = 1;
this.Builder.AwaitUnsafeOnCompleted(ref this.awaiter, ref this);
}
break;
case 1:
this.ResultOfAwait2 = this.awaiter.GetResult();
HelperMethods.Continuation2(this.ResultOfAwait2);
this.ResultToReturn = this.ResultOfAwait1 + this.ResultOfAwait2;
this.State = -2;
this.Builder.SetResult(this.ResultToReturn);
break;
}
}
catch (Exception exception)
{
this.State = -2;
this.Builder.SetException(exception);
}
}
[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
this.Builder.SetStateMachine(stateMachine);
}
}
6. 状态机与回调
状态机的核心思想是将代码按 await
拆分为多个部分,并通过回调链式执行。例如,MultiCallMethodAsync()
可以简化为以下形式:
internal static Task<int> MultiCallMethodAsync(int arg0, int arg1, int arg2, int arg3)
{
TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>();
try
{
HelperMethods.Before();
MethodAsync(arg0, arg1).ContinueWith(await1 =>
{
try
{
int resultOfAwait1 = await1.Result;
HelperMethods.Continuation1(resultOfAwait1);
MethodAsync(arg2, arg3).ContinueWith(await2 =>
{
try
{
int resultOfAwait2 = await2.Result;
HelperMethods.Continuation2(resultOfAwait2);
int resultToReturn = resultOfAwait1 + resultOfAwait2;
taskCompletionSource.SetResult(resultToReturn);
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
});
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
});
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
return taskCompletionSource.Task;
}
7. 使用 Task.Yield()
Task.Yield()
可以强制方法异步完成:
internal static async Task YeildAsync()
{
HelperMethods.Before();
await Task.Yield(); // 立即返回,不等待 continuation 代码执行
HelperMethods.Continuation(0);
}
其实现类似于:
internal static Task YeildAsync()
{
TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();
try
{
HelperMethods.Before();
Task yeild = new Task(() => { });
yeild.Start();
yeild.ContinueWith(await =>
{
try
{
HelperMethods.Continuation(0);
taskCompletionSource.SetResult(null);
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
});
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
return taskCompletionSource.Task;
}
总结
- async / await 是语法糖:编译后会生成状态机,将代码按
await
拆分为多个部分,并通过回调链式执行。 - 状态机:状态机负责管理异步操作的执行顺序和结果。
- Task.Yield():强制方法异步完成,类似于 JavaScript 的
setTimeout()
。