前言:
已经有很多文章讲解 async/await 了,此文仅给自己理解用。
此文章以下代码将重复使用,贯穿全文
public static string GetThreadId()
{
return Thread.CurrentThread.ManagedThreadId.ToString("000");
}
public static void TaskRun()
{
Console.WriteLine($"======== ThreadId:{GetThreadId()} Start.");
Thread.Sleep(3000);
Console.WriteLine($"======== ThreadId:{GetThreadId()} End.");
}
一、使用 async 和 await
使用 async/await 。
// btnAsync 按钮的点击事件
private void btnAsync_Click(object sender, EventArgs e)
{
Task task = NoReturnTask();
}
private async Task NoReturnTask()
{
Console.WriteLine($"==== ThreadId:{GetThreadId()} Start.");
await Task.Run(() => TaskRun());
Console.WriteLine($"==== ThreadId:{GetThreadId()} End.");
}
二、用代码实现 async/await
将 按钮1
的代码用 ILSpy 反编译以后,我们能发现 async 和 await 被编译成了一个状态机。
// btnAsync2 按钮的点击事件
private void btnAsync2_Click(object sender, EventArgs e)
{
var stateMachine = new AsyncStateMachine();
stateMachine.builder = AsyncTaskMethodBuilder.Create();
stateMachine.state = -1;
stateMachine.builder.Start(ref stateMachine);
Task task = stateMachine.builder.Task;
}
private class AsyncStateMachine : IAsyncStateMachine
{
public int state;
public AsyncTaskMethodBuilder builder;
private TaskAwaiter taskAwaiter;
public void MoveNext()
{
int num = state;
try
{
TaskAwaiter awaiter;
if (num != 0)
{
Console.WriteLine($"==== ThreadId:{GetThreadId()} Start.");
awaiter = Task.Run(() => TaskRun()).GetAwaiter();
if (!awaiter.IsCompleted)
{
num = state = 0;
taskAwaiter = awaiter;
AsyncStateMachine stateMachine = this;
builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
return;
}
}
else
{
awaiter = taskAwaiter;
taskAwaiter = default;
num = state = -1;
}
awaiter.GetResult();
Console.WriteLine($"==== ThreadId:{GetThreadId()} End.");
}
catch (Exception ex)
{
state = -2;
builder.SetException(ex);
return;
}
state = -2;
builder.SetResult();
}
void IAsyncStateMachine.MoveNext()
{
MoveNext();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
SetStateMachine(stateMachine);
}
}
整个状态机的执行流程从 AsyncTaskMethodBuilder
的 Start
方法触发 IAsyncStateMachine.MoveNext
方法开始。
在状态机中 用 Task.Run
执行我们需要等待的任务,用 TaskAwaiter
监控任务是否完成。
当等待任务完成后,将会有一个回调重新调用 IAsyncStateMachine.MoveNext
方法,
这时状态机的 state 已经为 0,执行到 awaiter.GetResult
方法获得结果。