# 概念
# 同步与异步
  • 同步:执行完一个任务之后才会执行下一个任务

  • 异步:执行一个任务不管是否完成,就开始执行下一个任务,如果任务没有结果则任务完成之后会通过状态、通知、回调告知完成。

  • 区别:任务之间是否会等待完成才开始执行。

# 阻塞与非阻塞
  • 阻塞:线程挂起,等待某个操作执行完成,期间 CPU 不会分给时间片给该线程,该线程无法执行其他工作。
  • 非阻塞:就算某个方法没有执行完,线程也会返回。
  • 区别:调用者是否一直等待结果,期间不执行其他代码。
# 同步异步与阻塞非阻塞
  • 区别:
    • 同步与异步关注的是如何得到结果以及得到结果后如何通知调用者完成
    • 阻塞与非阻塞关注的是如何等待结果,是线程等待着完成还是先做其他的事情等完成后通知、回调或者轮训状态。
# 异步使用场景
  • IO 密集型:网络请求数据、数据库访问或者读写文件系统,这一类的操作 CPU 不直接参与,而是需要等待某些事情完成,使用按手印 async/await 并通过 TaskCompletionSource 来实现通知 IO 操作已经完成。
  • CPU 密集型:不包含各种 IO 操作
# Async/Await 关键字
  • 作用:只是在方法中加入 async 关键字并没有什么作用,只是为了在方法中能够使用 await 关键字。而 await 的作用是,当 Task 任务未完成,会马上返回至调用者,相当于暂停方法的执行,并且在 Task 任务完成之后,根据同步上下文在原线程或者在线程池中挑选一个线程或者创建一个线程获得 Task 返回结果。如果发生异常则在现有的调用栈中重新抛出异常并继续执行后续代码。
# 反编译代码
  • 只有 Async,空方法

async的作用就是初始化一个状态机

public async Task AsyncTask1()
{
    // 空方法返回 Task
}
// 反编译 IL 进行整理
public Task Asyncvoid()
{
   AsyncTaskStateMachine1 stateMachine = new AsyncTaskStateMachine1()
   {
     builder = AsyncTaskMethodBuilder.Create(),
     asyncTask = this,
     state = -1
   };
   // 调用 stateMachine.MoveNext () 方法
   stateMachine.builder.Start(ref stateMachine);
   return stateMachine.builder.Task;
}
/// <summary>
/// 状态机
/// 包含 MoveNext 和 SetStateMachine 两个方法
/// </summary>
private struct AsyncTaskStateMachine1 : IAsyncStateMachine
{
    public int state;
    public AsyncTaskMethodBuilder builder;
    public AsyncTask asyncTask;
    private void MoveNext()
    {
        int num = state;
        try
        {
        }
        catch (Exception ex)
        {
            state = -2;
            builder.SetException(ex);
            return;
        }
        state = -2; //-2 状态表示已完成
        builder.SetResult();// 标记为完成状态
    }
    private void SetStateMachine(IAsyncStateMachine stateMachine)
    {
    }
    void IAsyncStateMachine.MoveNext()
    {
        this.MoveNext();
    }
    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        this.SetStateMachine(stateMachine);
    }
}
  • 有 Async 和 Await
public async Task AsyncTask2()
{
    await Task.CompletedTask;
}
private struct AsyncTaskStateMachine2 : IAsyncStateMachine
{
    public int state;
    public AsyncTaskMethodBuilder builder;
    public AsyncTask asyncTask;
    // 相比没有写 await,多了一个 TaskAwaiter
    private TaskAwaiter taskAwaiterField;
    private void MoveNext()
    {
        int num = state;
        try
        {
            // 声明了一个局部变量 awaiter
            TaskAwaiter awaiter;
            if (num != 0)
            {
                // 获取当前 Task 的 awaiter
                awaiter = Task.CompletedTask.GetAwaiter();
                // 判断当前任务是否完成
                if (!awaiter.IsCompleted)
                {
                    num = 0;
                    taskAwaiterField = awaiter;
                    AsyncTaskStateMachine2 stateMachine = this;
                    // 如果未完成,则取捕获同步上下文,并通过委托回调继续执行本状态机的 MoveNext 方法
                    builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
                    // 直接返回,并不会执行 GetResult 方法,而是通过上一步的回调到本方法,继续执行后续代码
                    return;
                }
            }
            else
            {
                awaiter = taskAwaiterField;
                taskAwaiterField = default(TaskAwaiter);
                num = -1;
            }
            awaiter.GetResult();
        }
        catch (Exception ex)
        {
            state = -2;
            builder.SetException(ex);
            return;
        }
        state = -2; //-2 状态表示已完成
        builder.SetResult();// 标记为完成状态
    }
    private void SetStateMachine(IAsyncStateMachine stateMachine)
    {
    }
    void IAsyncStateMachine.MoveNext()
    {
        this.MoveNext();
    }
    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        this.SetStateMachine(stateMachine);
    }
}
  • 空方法返回 Task<void>

与返回Task一致

  • IL 中关键方法解析
# AsyncTaskMethodBuilder<TResult> 中 Create () 和 Start () 方法
public static AsyncTaskMethodBuilder<TResult> Create()
{
    // 返回 AsyncTaskMethodBuilder<TResult > 实例
    return default(AsyncTaskMethodBuilder<TResult>);
}
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
    if (stateMachine == null) throw new ArgumentNullException("stateMachine");
    Contract.EndContractBlock();
    ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
    RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
        ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
        // 其他的先不管什么意思,其目的就是调用 MoveNext 方法
        stateMachine.MoveNext();
    }
    finally
    {
        ecs.Undo();
    }
}
# MoveNext 中的 AsyncTaskMethodBuilder<TResult>.AwaitUnsafeOnCompleted(awaiter,stateMachine) 方法
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine
{
            try
            {
                AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
                //GetComopletionAction 方法获取回调方法
                var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
                
                Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");
                if (m_coreState.m_stateMachine == null)
                {
                    var builtTask = this.Task;
                    Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
                    m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, builtTask);
                }
                
                // 调用了 TaskAwaiter 的 UnsafeOnCompleted 的方法
                awaiter.UnsafeOnCompleted(continuation);
            }
            catch (Exception e)
            {
                AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
            }
        }
# 先看上面的 GetCompletionAction 方法
[SecuritySafeCritical]
internal Action GetCompletionAction(Task taskForTracing, ref MoveNextRunner runnerToInitialize)
{
    Contract.Assert(m_defaultContextAction == null || m_stateMachine != null,
       "Expected non-null m_stateMachine on non-null m_defaultContextAction");
    Debugger.NotifyOfCrossThreadDependency();
    // 捕获执行上下文
    var capturedContext = ExecutionContext.FastCapture();
    Action action;
    // 定义了一个 MoveNext 的 Runner, 然后给 Runner 赋值
    MoveNextRunner runner;
    if (capturedContext != null && capturedContext.IsPreAllocatedDefault)
    {
        // Get the cached delegate, and if it's non-null, return it.
        action = m_defaultContextAction;
        if (action != null)
        {
            Contract.Assert(m_stateMachine != null, "If the delegate was set, the state machine should have been as well.");
            return action;
        }
        runner = new MoveNextRunner(capturedContext, m_stateMachine);
        // 将 Runner 的 Run 方法通过 Action 传递,Run 方法其实是在执行上下文当中执行 MoveNext 方法
        action = new Action(runner.Run);
        if (taskForTracing != null)
        {
            m_defaultContextAction = action = OutputAsyncCausalityEvents(taskForTracing, action);
        }
        else
        {
            m_defaultContextAction = action;
        }
    }
    else
    {
        runner = new MoveNextRunner(capturedContext, m_stateMachine);
        action = new Action(runner.Run);
        if (taskForTracing != null)
        {
            action = OutputAsyncCausalityEvents(taskForTracing, action);
        }
    }
    if (m_stateMachine == null)
        runnerToInitialize = runner;
    // 返回 Action 委托
    return action;
}
# 再看 TaskAwaiter 的 UnsafeOnCompleted 方法
[SecurityCritical]
public void UnsafeOnCompleted(Action continuation)
{
    TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, 			          flowExecutionContext:false);
    
}
[MethodImplAttribute(MethodImplOptions.NoInlining)]
[SecurityCritical]
internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, 			bool flowExecutionContext)
{
   if (continuation == null) throw new ArgumentNullException("continuation");
   StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
 
   // If TaskWait* ETW events are enabled, trace a beginning event for this await
   // and set up an ending event to be traced when the asynchronous await completes.
   if ( TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled)
   {
       continuation = OutputWaitEtwEvents(task, continuation);
   }
 
   // Set the continuation onto the awaited task.
   // 获取 TaskContinution 并把 Action 放入其中,调用其 Run 方法,里面的 Run 方法也是执行延续后回调
   task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext, ref 		 stackMark);
}
# SetContinuationForAwait 方法
  • 根据各种条件创建不同的 TaskContinuation ,根据 Continution 定义的规则,执行里面的 Run 方法。
[SecurityCritical]
internal void SetContinuationForAwait(Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext, ref StackCrawlMark stackMark)
{
    Contract.Requires(continuationAction != null);
    TaskContinuation tc = null;
    if (continueOnCapturedContext)
    {
        var syncCtx = SynchronizationContext.CurrentNoFlow;
        if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
        {
            tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext, ref stackMark);
        }
        else
        {
            var scheduler = TaskScheduler.InternalCurrent;
            if (scheduler != null && scheduler != TaskScheduler.Default)
            {
                tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext, ref stackMark);
            }
        }
    }
    if (tc == null && flowExecutionContext)
    {
        tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true, stackMark: ref stackMark);
    }
    
    if (tc != null)
    {
        if (!AddTaskContinuation(tc, addBeforeOthers: false))
            // 调用 continution 的 Run 方法,按照指定的规则执行
            tc.Run(this, bCanInlineContinuationTask: false);
    }
    else
    {
        if (!AddTaskContinuation(continuationAction, addBeforeOthers: false))
            //TaskContinution 最后都没有就执行非安全的方法
            // 实际上是执行 ThreadPool.UnsafeQueueUserWorkItem () 方法
            AwaitTaskContinuation.UnsafeScheduleAction(continuationAction, this);
    }
}

补充中...

# 参考链接

使用 async 和 await 进行异步编程

.Net 基于任务的异步模式

ConfigureAwait 讲解

ExecutionContext vs SynchronizationContext知乎链接

github 异步编程注意事项

异步 IL 反编译