async await随笔

一些随笔

理解一些名词(简单的说,具体定义可百度)

并发(concurrency):同一时间段内执行多个任务,但是在同一时刻你只可以执行一个任务。

并行(parallellism):同一时刻执行多个任务。

同步异步关注的是消息通信机制

同步(Synchronous):调用方必须等待这个调用返回结果才能继续执行。

异步(Asynchronous):调用方不会立刻得到结果,而是调用发出后调用者可以继续后续的操作,而被调用者后续,当完成时会通知调用者完成后续操作。

async await

我们一般将async修饰的方法叫做 "异步方法" ,这并不一定意味着方法是异步执行的。这也不意味着该方法是异步的。它只意味着编译器对方法执行一些特殊的转换。

示例1


static async Task Main() 
{
    await Task.Run(()=>Console.WriteLine("111"));
    Console.Write("22");
}

生成的C#代码

1.委托,编译器会给我们生成一个类和一个实例方法


// ()=>Console.WriteLine("111")
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
    public static readonly <>c <>9 = new <>c();

    public static Action <>9__0_0;

    internal void <Main>b__0_0()
    {
        Console.WriteLine("111");
    }
}

2.编译器为async 生成的代码


[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <Main>d__0 : IAsyncStateMachine
{
    public int <>1__state;

    public AsyncTaskMethodBuilder <>t__builder;

    private TaskAwaiter <>u__1;

    private void MoveNext()
    {
        int num = <>1__state;
        try
        {
            TaskAwaiter awaiter;
            if (num != 0)
            {
                awaiter = Task.Run(<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Action(<>c.<>9.<Main>b__0_0))).GetAwaiter();
                if (!awaiter.IsCompleted)
                {
                    num = (<>1__state = 0);
                    <>u__1 = awaiter;
                    <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
                    return;
                }
            }
            else
            {
                awaiter = <>u__1;
                <>u__1 = default(TaskAwaiter);
                num = (<>1__state = -1);
            }
            awaiter.GetResult();
            Console.Write("22");
        }
        catch (Exception exception)
        {
            <>1__state = -2;
            <>t__builder.SetException(exception);
            return;
        }
        <>1__state = -2;
        <>t__builder.SetResult();
    }

    void IAsyncStateMachine.MoveNext()
    {
        //ILSpy generated this explicit interface implementation from .override directive in MoveNext
        this.MoveNext();
    }

    [DebuggerHidden]
    private void SetStateMachine(IAsyncStateMachine stateMachine)
    {
        <>t__builder.SetStateMachine(stateMachine);
    }

    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
        this.SetStateMachine(stateMachine);
    }
}


分析状态机每个字段

编译器为 async修饰的方法 生成的了一个结构体 <Main>d__0,实现了IAsyncStateMachine接口,这个接口有2个方法:

void MoveNext() 执行下一步

void SetStateMachine(IAsyncStateMachine stateMachine) 设置状态

为什么会各自实现2个 是因为ILSpy通过setstatemmachine中的.override指令生成了这个显式的接口实现,这个不用管.

public int <>1__state 状态值

public AsyncTaskMethodBuilder <>t__builder Provides a builder for asynchronous methods that return(为返回的异步方法提供构建器),它保存完成的任务(非常类似于TaskCompletionSource<T>类型),并管理状态机的状态转换。

private TaskAwaiter <>u__1 Provides an awaiter for awaiting a (提供一个等候者),它封装了一个任务,并在需要时安排任务的延续(类似于Task.ContinueWith(), 延续的是封装的是 await 后 未完成的),

上述例子 如果Task.Run().GetAwaiter(); 状态不是完成,IsCompleted = false, 则会把后续 Task.Run(<>c.<>9__0_0),和cw("222") 作为一个延续。


分析执行流程


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

  1. Main函数执行, 初始化结构体<Main>d__0,初始化状态机状态为-1,关联要执行的状态机[AsyncStateMachine(typeof(<Main>d__0))],并Create一个异步方法构建器, ;

  2. 执行关联的状态机 stateMachine.<>t__builder.Start(ref stateMachine) 参数为关联的状态机<Main>d__0

  3. start发生了什么? 先只看核心的:在正确的执行上下文中使用 调用了 stateMachine.MoveNext();


/// <summary>Initiates the builder's execution with the associated state machine.</summary>
/// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
/// <param name="stateMachine">The state machine instance, passed by reference.</param>
[DebuggerStepThrough]
public static void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
    if (stateMachine == null) // TStateMachines are generally non-nullable value types, so this check will be elided
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);
    }

    // enregistrer variables with 0 post-fix so they can be used in registers without EH forcing them to stack
    // Capture references to Thread Contexts
    Thread currentThread0 = Thread.CurrentThread;
    Thread currentThread = currentThread0;
    ExecutionContext? previousExecutionCtx0 = currentThread0._executionContext;

    // Store current ExecutionContext and SynchronizationContext as "previousXxx".
    // This allows us to restore them and undo any Context changes made in stateMachine.MoveNext
    // so that they won't "leak" out of the first await.
    ExecutionContext? previousExecutionCtx = previousExecutionCtx0;
    SynchronizationContext? previousSyncCtx = currentThread0._synchronizationContext;

    try
    {
        stateMachine.MoveNext();
    }
    finally
    {
        // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack
        SynchronizationContext? previousSyncCtx1 = previousSyncCtx;
        Thread currentThread1 = currentThread;
        // The common case is that these have not changed, so avoid the cost of a write barrier if not needed.
        if (previousSyncCtx1 != currentThread1._synchronizationContext)
        {
            // Restore changed SynchronizationContext back to previous
            currentThread1._synchronizationContext = previousSyncCtx1;
        }

        ExecutionContext? previousExecutionCtx1 = previousExecutionCtx;
        ExecutionContext? currentExecutionCtx1 = currentThread1._executionContext;
        if (previousExecutionCtx1 != currentExecutionCtx1)
        {
            ExecutionContext.RestoreChangedContextToThread(currentThread1, previousExecutionCtx1, currentExecutionCtx1);
        }
    }
}

ExecutionContext(执行上下文)

SynchronizationContext(同步上下文)

上一篇:Unity协程和C#迭代器的关系


下一篇:ADO PutCollect操作,MoveNext或Update后,程序发生异常,原因分析