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;
}
-
Main函数执行,关联要执行的状态机,并Create一个异步方法构建器, 初始化结构体
<Main>d__0
,初始化状态机状态为-1; -
执行关联的状态机
stateMachine.<>t__builder.Start(ref stateMachine)
参数为关联的状态机<Main>d__0
。 -
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);
}
}
}
// TODO FOR HERE
ExecutionContext(执行上下文)
SynchronizationContext(同步上下文)