Async与Await异步模式源码剖析

作者:Chdon 发布时间: 2025-09-30 阅读量:26 评论数:0

一、案例代码与反编译分析

1.1 原始示例代码

using System;
using System.Threading.Tasks;

private static async Task Main(string[] args)
{
	Console.WriteLine(await Task.Factory.StartNew(() => Task.FromResult(0)));
}

1.2 反编译核心结构

使用ILSpy反编译后代码, 切换到C# 4.0 / VS 2010 以查看生成的状态机

1.2.1 Main函数

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

[AsyncStateMachine(typeof(<Main>d__0))]
[DebuggerStepThrough]
private static Task Main(string[] args)
{
    <Main>d__0 stateMachine = new <Main>d__0();
    stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.args = args;
    stateMachine.<>1__state = -1;
    stateMachine.<>t__builder.Start(ref stateMachine);
    return stateMachine.<>t__builder.Task;
}

1.2.2 状态机代码

仅显示核心函数MoveNext

private sealed class <Main>d__0 : IAsyncStateMachine
{
    public int <>1__state;

    public AsyncTaskMethodBuilder <>t__builder;

    public string[] args;

    private Task<int> <res>5__1;

    private Task<int> <>s__2;

    private TaskAwaiter<Task<int>> <>u__1;

    private void MoveNext()
    {
        int num = <>1__state;
        try
        {
            TaskAwaiter<Task<int>> awaiter;
            if (num != 0)
            {
                awaiter = Task.Factory.StartNew(() => Task.FromResult(0)).GetAwaiter();
                if (!awaiter.IsCompleted)
                {
                    num = (<>1__state = 0);
                    <>u__1 = awaiter;
                    <Main>d__0 stateMachine = this;
                    <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
                    return;
                }
            }
            else
            {
                awaiter = <>u__1;
                <>u__1 = default(TaskAwaiter<Task<int>>);
                num = (<>1__state = -1);
            }
            <>s__2 = awaiter.GetResult();
            <res>5__1 = <>s__2;
            <>s__2 = null;
            Console.WriteLine(<res>5__1);
        }
        catch (Exception exception)
        {
            <>1__state = -2;
            <res>5__1 = null;
            <>t__builder.SetException(exception);
            return;
        }
        <>1__state = -2;
        <res>5__1 = null;
        <>t__builder.SetResult();
    }
    ...
}

二、异步状态机工作机制

2.1 初始化流程

  1. 创建状态机实例
    生成继承 IAsyncStateMachine 的私有类实例,保存上下文信息
  2. 构建异步方法组件
    AsyncTaskMethodBuilder.Create() 创建异步操作的核心控制器
  3. 设置初始状态
    通过 <>1__state = -1 标记为初始执行状态
  4. 启动状态机
    调用构建器的 Start() 方法触发首次 MoveNext 执行

2.2 执行阶段分析

Snipaste_2025-09-30_13-04-07.bmp

2.2.1 第一次调用MoveNext

通过执行AsyncTaskMethodBuilderStart方法,进行状态机MoveNext的第一次调用。

2.2.1.1 此次调用MoveNext会产生两种结果:

  1. Task同步完成,直接返回Task的Result。
    • 一般会出现在类似Task t = Task.FromResult(0)这种情况,创建完Task, 能够立即完成的。
    • 示例代码使用的是Task.Factory.StartNew(),不会出现这种情况。
  2. Task未同步完成,进入等待状态。

2.2.1.2 源码

private void MoveNext()
{
    int num = <>1__state;
    try
    {
        TaskAwaiter<Task<int>> awaiter;
        // 当前num==-1, 进入到此if分支
        if (num != 0)
        {
            // 获取当前Task的Awaiter=>TaskAwaiter
            awaiter = Task.Factory.StartNew(() => Task.FromResult(0)).GetAwaiter();
            // 当前Task未直接完成
            if (!awaiter.IsCompleted)
            {
                num = (<>1__state = 0);
                <>u__1 = awaiter;
                <Main>d__0 stateMachine = this;
                // 进入等待状态
                <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
                return;
            }
        }
        // 不会进入此分支
        else
        {
            awaiter = <>u__1;
            <>u__1 = default(TaskAwaiter<Task<int>>);
            num = (<>1__state = -1);
        }
        // 如果当前任务同步完成,直接获取当前Task结果
        <>s__2 = awaiter.GetResult();
        <res>5__1 = <>s__2;
        <>s__2 = null;
        Console.WriteLine(<res>5__1);
    }
    catch (Exception exception)
    {
        <>1__state = -2;
        <res>5__1 = null;
        <>t__builder.SetException(exception);
        return;
    }
    <>1__state = -2;
    <res>5__1 = null;
    <>t__builder.SetResult();
}

2.2.2 准备进入等待状态

通过调用<>t__builder.AwaitUnsafeOnCompleted进入等待状态。

2.2.2.1 源码

internal static void AwaitUnsafeOnCompleted<TAwaiter>(
    ref TAwaiter awaiter, IAsyncStateMachineBox box)
    where TAwaiter : ICriticalNotifyCompletion
{
    // 传入awaiter为TaskAwaiter, 进入此if分支
    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);
    }
    ...
}

2.2.3 追加MoveNext方法到Task延续任务。

通过调用TaskAwaiter.UnsafeOnCompletedInternal将异步状态机中的MoveNext追加到Task的延续对象中

2.2.3.1 源码

internal void UnsafeSetContinuationForAwait(IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext)
{
    // Create the best AwaitTaskContinuation object given the request.
    // If this remains null by the end of the function, we can use the
    // continuationAction directly without wrapping it.
    TaskContinuation? tc;

    if (continueOnCapturedContext)
    {
        if (SynchronizationContext.Current is SynchronizationContext syncCtx && syncCtx.GetType() != typeof(SynchronizationContext))
        {
            tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, stateMachineBox.MoveNextAction, flowExecutionContext: false);
            goto HaveTaskContinuation;
        }

        if (TaskScheduler.InternalCurrent is TaskScheduler scheduler && scheduler != TaskScheduler.Default)
        {
            tc = new TaskSchedulerAwaitTaskContinuation(scheduler, stateMachineBox.MoveNextAction, flowExecutionContext: false);
            goto HaveTaskContinuation;
        }
    }

    // Otherwise, add the state machine box directly as the continuation.
    // If we're unable to because the task has already completed, queue it.
    if (!AddTaskContinuation(stateMachineBox, addBeforeOthers: false))
    {
        ThreadPool.UnsafeQueueUserWorkItemInternal(stateMachineBox, preferLocal: true);
    }
    return;

    HaveTaskContinuation:
    if (!AddTaskContinuation(tc, addBeforeOthers: false))
    {
        tc.Run(this, canInlineContinuationTask: false);
    }
}

2.2.4 完成Task,执行延续任务。

在Task执行完成后,会调用FinishContinuations执行其延续任务

2.2.4.1 执行延续任务时,调用异步状态机中的MoveNext方法,恢复代码执行。

2.2.4.2 源码

仅列出延续任务仅是单个的情况,多个(不仅包含异步状态机的MoveNext)的类似

private void RunContinuations(object continuationObject) // separated out of FinishContinuations to enable it to be inlined
{
    bool canInlineContinuations =
        (m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) == 0 &&
        RuntimeHelpers.TryEnsureSufficientExecutionStack();

    switch (continuationObject)
    {
        // Handle the single IAsyncStateMachineBox case.  This could be handled as part of the ITaskCompletionAction
        // but we want to ensure that inlining is properly handled in the face of schedulers, so its behavior
        // needs to be customized ala raw Actions.  This is also the most important case, as it represents the
        // most common form of continuation, so we check it first.
        case IAsyncStateMachineBox stateMachineBox:
            AwaitTaskContinuation.RunOrScheduleAction(stateMachineBox, canInlineContinuations);
            LogFinishCompletionNotification();
            return;

        // Handle the single Action case.
        case Action action:
            AwaitTaskContinuation.RunOrScheduleAction(action, canInlineContinuations);
            LogFinishCompletionNotification();
            return;

        // Handle the single TaskContinuation case.
        case TaskContinuation tc:
            tc.Run(this, canInlineContinuations);
            LogFinishCompletionNotification();
            return;

        // Handle the single ITaskCompletionAction case.
        case ITaskCompletionAction completionAction:
            RunOrQueueCompletionAction(completionAction, canInlineContinuations);
            LogFinishCompletionNotification();
            return;
    }

    // Not a single; it must be a list.
    List<object?> continuations = (List<object?>)continuationObject;

    //
    // Begin processing of continuation list
    //

    ...
}

2.2.5 MoveNext第二次

第二次调用MoveNext方法后,会恢复后续代码的执行。

2.2.5.1 源码

private void MoveNext()
{
    int num = <>1__state;
    try
    {
        TaskAwaiter<Task<int>> awaiter;
        if (num != 0)
        {
            awaiter = Task.Factory.StartNew(() => Task.FromResult(0)).GetAwaiter();
            if (!awaiter.IsCompleted)
            {
                num = (<>1__state = 0);
                <>u__1 = awaiter;
                <Main>d__0 stateMachine = this;
                <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
                return;
            }
        }
        // 此时num==0, 进入此分支
        else
        {
            awaiter = <>u__1;
            <>u__1 = default(TaskAwaiter<Task<int>>);
            num = (<>1__state = -1);
        }
        // 获取执行结果
        <>s__2 = awaiter.GetResult();
        <res>5__1 = <>s__2;
        <>s__2 = null;
        // 执行await后续的代码
        Console.WriteLine(<res>5__1);
    }
    catch (Exception exception)
    {
        <>1__state = -2;
        <res>5__1 = null;
        <>t__builder.SetException(exception);
        return;
    }
    <>1__state = -2;
    <res>5__1 = null;
    <>t__builder.SetResult();
}

三、同步上下文捕获

3.1 默认情况

在执行阶段2.2.2 准备进入等待状态时, 会正常捕获当前同步上下文。

3.1.1 源码

// struct: AsyncTaskMethodBuilder<TResult> 
internal static void AwaitUnsafeOnCompleted<TAwaiter>(
            ref TAwaiter awaiter, IAsyncStateMachineBox box)
            where TAwaiter : ICriticalNotifyCompletion
{
    // The null tests here ensure that the jit can optimize away the interface
    // tests when TAwaiter is a ref type.
    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);
    }
}

// class: Task
internal void UnsafeSetContinuationForAwait(IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext)
{
    // Create the best AwaitTaskContinuation object given the request.
    // If this remains null by the end of the function, we can use the
    // continuationAction directly without wrapping it.
    TaskContinuation? tc;

    // If the caller wants to continue on the current context/scheduler and there is one,
    // fall back to using the state machine's delegate.
    if (continueOnCapturedContext)
    {
        if (SynchronizationContext.Current is SynchronizationContext syncCtx && syncCtx.GetType() != typeof(SynchronizationContext))
        {
            tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, stateMachineBox.MoveNextAction, flowExecutionContext: false);
            goto HaveTaskContinuation;
        }

        if (TaskScheduler.InternalCurrent is TaskScheduler scheduler && scheduler != TaskScheduler.Default)
        {
            tc = new TaskSchedulerAwaitTaskContinuation(scheduler, stateMachineBox.MoveNextAction, flowExecutionContext: false);
            goto HaveTaskContinuation;
        }
    }
}

3.2 添加ConfigureAwait(false)

await Taskxxx()后追加.ConfigureAwait(false), 即await Taskxxx().ConfigureAwait(false)。则会生成ConfiguredTaskAwaiter, 阻止同步上下文切换。

3.2.2 源码

// struct: AsyncTaskMethodBuilder<TResult> 
internal static void AwaitUnsafeOnCompleted<TAwaiter>(
            ref TAwaiter awaiter, IAsyncStateMachineBox box)
            where TAwaiter : ICriticalNotifyCompletion
{
    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);
    }
}

// class: Task
internal void UnsafeSetContinuationForAwait(IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext)
{
    // Otherwise, add the state machine box directly as the continuation.
    // If we're unable to because the task has already completed, queue it.
    if (!AddTaskContinuation(stateMachineBox, addBeforeOthers: false))
    {
        ThreadPool.UnsafeQueueUserWorkItemInternal(stateMachineBox, preferLocal: true);
    }
    return;
}

四、同步等待Task结果

4.1 Task.Result vs Task.GetAwaiter().GetResult()

4.1.1 Task.Result

  • 如果任务未完成,会同步阻塞当前线程直到任务完成。
  • 返回任务的结果(若任务是 Task)。
  • 异常处理:如果任务抛出异常,异常会被包装成 AggregateException 抛出。

4.1.2 Task.GetAwaiter().GetResult()

  • 如果任务未完成,也会同步阻塞当前线程直到任务完成。
  • 返回任务的结果(若任务是 Task)。
  • 异常处理:直接抛出任务原始的异常(而非 AggregateException)。

4.1.3 总结

  • 在未明确需要处理AggregateException异常的情况下,优先选用Task.GetAwaiter().GetResult()
  • 两者均会造成当前线程阻塞,所以优先使用await来等待Task完成并获取执行结果。

评论