文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么使用c#异步操作async await状态机

2023-07-05 05:58

关注

本篇内容介绍了“怎么使用c#异步操作async await状态机”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

async await是语法糖

大家应该都比较清楚async和await这对关键字是一组语法糖,关于语法糖大家可以理解为,编码过程中写了一个关键字,但是编译的时候会把它编译成别的东西,主要是用来提升开发效率。比如我有一段关于async和await相关的代码,如下所示

var taskOne = await TaskOne();Console.WriteLine(taskOne);Console.ReadLine();   static async Task<string> TaskOne(){    var httpResponse = await ClassFactory.Client.GetAsync("https://www.cnblogs.com");    var content = await httpResponse.Content.ReadAsStringAsync();    return content;}public class ClassFactory{    public static HttpClient Client = new HttpClient();}

这段代码是基于c#顶级语句声明的,它是缺省Main方法的,不过在编译的时候编译器会帮我们补齐Main方法,因为执行的时候JIT需要Main方法作为执行入口。关于如何查看编译后的代码。我经常使用的是两个工具,分别是ILSpydnSpy。这俩工具的区别在于ILSpy生成的代码更清晰,dnSpy生成的源码是可以直接调试的。需要注意的是如果使用的是ILSpy如果查看语法糖本质的话,需要在ILSpy上选择比语法糖版本低的版本,比如c# async和await关键字是在c# 5.0版本中引入的,所以我们这里我们在ILSpy里需要选择c#4.0或以下版本,入下图所示

怎么使用c#异步操作async await状态机

如果使用的是dnSpy的话,需要在调试-->选项-->反编译器中设置相关选项,如下所示

怎么使用c#异步操作async await状态机

这样就可以看到编译后生成的代码了。

生成的状态机

围绕上面的示例我这里使用的Debug模式下编译生成的dll使用的ILSpy进行反编译,因为这里我需要让编译的源码看起来更清晰一点,而不是调试。如下所示首先看Main方法

//因为我们上面代码var taskOne = await TaskOne()//使用了await语法糖,所以被替换成了状态机调用[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;//设置状态-1stateMachine.<>1__state = -1;//启动状态机stateMachine.<>t__builder.Start(ref stateMachine);return stateMachine.<>t__builder.Task;}//这是系统默认帮我们生成的static void Main的入口方法[SpecialName][DebuggerStepThrough]private static void <Main>(string[] args){//同步调用<Main>$方法<Main>$(args).GetAwaiter().GetResult();}

上面的代码就是编译器为我们生成的Main方法,通过这里我们可以得到两条信息

通过上面我们可以看到<<Main>$>d__0 这个类是编译器帮我们生成的,我们可以看一下生成的代码

[CompilerGenerated]private sealed class <<Main>$>d__0 : IAsyncStateMachine{public int <>1__state;public AsyncTaskMethodBuilder <>t__builder;public string[] args;private string <taskOne>5__1;private string <>s__2;[System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })]private TaskAwaiter<string> <>u__1;private void MoveNext(){int num = <>1__state;try{TaskAwaiter<string> awaiter;//num的值来自<>1__state,由于在创建状态机的时候传递的是-1所以一定会走到这个逻辑if (num != 0){//调用TaskOne方法,也就是上面我们写的业务方法//这个方法返回的是TaskAwaiter<>实例,以为我们TaskOne方法是异步方法awaiter = <<Main>$>g__TaskOne|0_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<string>);num = (<>1__state = -1);}//调用GetResult()方法获取异步执行结果<>s__2 = awaiter.GetResult();<taskOne>5__1 = <>s__2;<>s__2 = null;//这里对应我们上面的输出调用TaskOne方法的结果Console.WriteLine(<taskOne>5__1);Console.ReadLine();}catch (Exception exception){<>1__state = -2;<taskOne>5__1 = null;<>t__builder.SetException(exception);return;}<>1__state = -2;<taskOne>5__1 = null;<>t__builder.SetResult();}void IAsyncStateMachine.MoveNext(){this.MoveNext();}[DebuggerHidden]private void SetStateMachine([System.Runtime.CompilerServices.Nullable(1)] IAsyncStateMachine stateMachine){}void IAsyncStateMachine.SetStateMachine([System.Runtime.CompilerServices.Nullable(1)] IAsyncStateMachine stateMachine){this.SetStateMachine(stateMachine);}}

这里的代码可以看到编译器生成的代码,其实这就是对应上面我们写的代码

var taskOne = await TaskOne();Console.WriteLine(taskOne);Console.ReadLine();

因为我们使用了await关键字,所以它帮我们生成了IAsyncStateMachine类,里面的核心逻辑咱们待会在介绍,因为今天的主题TaskOne方法还没介绍完成呢,TaskOne生成的代码如下所示

//TaskOne方法编译时生成的代码[CompilerGenerated]private sealed class <<<Main>$>g__TaskOne|0_0>d : IAsyncStateMachine{public int <>1__state;public AsyncTaskMethodBuilder<string> <>t__builder;private HttpResponseMessage <httpResponse>5__1;private string <content>5__2;private HttpResponseMessage <>s__3;private string <>s__4;[System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })]private TaskAwaiter<HttpResponseMessage> <>u__1;[System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })]private TaskAwaiter<string> <>u__2;private void MoveNext(){int num = <>1__state;string result;try{//因为我们使用了两次await所以这里会有两个TaskAwaiter<>实例//var httpResponse = await ClassFactory.Client.GetAsync("https://www.cnblogs.com");                        //var content = await httpResponse.Content.ReadAsStringAsync();TaskAwaiter<string> awaiter;TaskAwaiter<HttpResponseMessage> awaiter2;if (num != 0){if (num == 1){awaiter = <>u__2;<>u__2 = default(TaskAwaiter<string>);num = (<>1__state = -1);goto IL_0100;}//这段逻辑针对的是我们手写的这段代码//await ClassFactory.Client.GetAsync("https://www.cnblogs.com")awaiter2 = ClassFactory.Client.GetAsync("https://www.cnblogs.com").GetAwaiter();                                //判断任务是否完成if (!awaiter2.IsCompleted){num = (<>1__state = 0);<>u__1 = awaiter2;<<<Main>$>g__TaskOne|0_0>d stateMachine = this;<>t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine);return;}}else{awaiter2 = <>u__1;<>u__1 = default(TaskAwaiter<HttpResponseMessage>);num = (<>1__state = -1);}//同步获取HttpResponseMessage结果实例<>s__3 = awaiter2.GetResult();<httpResponse>5__1 = <>s__3;<>s__3 = null;//这段代码对应生成的则是await httpResponse.Content.ReadAsStringAsync()awaiter = <httpResponse>5__1.Content.ReadAsStringAsync().GetAwaiter();if (!awaiter.IsCompleted){num = (<>1__state = 1);<>u__2 = awaiter;<<<Main>$>g__TaskOne|0_0>d stateMachine = this;<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);return;}goto IL_0100;IL_0100://同步获取httpResponse.Content.ReadAsStringAsync()放的结果<>s__4 = awaiter.GetResult();<content>5__2 = <>s__4;<>s__4 = null;result = <content>5__2;}catch (Exception exception){<>1__state = -2;<httpResponse>5__1 = null;<content>5__2 = null;<>t__builder.SetException(exception);return;}<>1__state = -2;<httpResponse>5__1 = null;<content>5__2 = null;//调用AsyncTaskMethodBuilder<>方法放置httpResponse.Content.ReadAsStringAsync()结果<>t__builder.SetResult(result);}void IAsyncStateMachine.MoveNext(){this.MoveNext();}[DebuggerHidden]private void SetStateMachine([System.Runtime.CompilerServices.Nullable(1)] IAsyncStateMachine stateMachine){}void IAsyncStateMachine.SetStateMachine([System.Runtime.CompilerServices.Nullable(1)] IAsyncStateMachine stateMachine){this.SetStateMachine(stateMachine);}}

到这里为止,这些方法就是编译器帮我们生成的代码,也就是这些代码就在生成好的dll里的。

启动状态机

接下来我们分析一下状态机的调用过程,回到上面的stateMachine.<>t__builder.Start(ref stateMachine)这段状态机启动代码,我们跟进去看一下里面的逻辑

[MethodImpl(MethodImplOptions.AggressiveInlining)][DebuggerStepThrough]public void Start<[Nullable(0)] TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine{//调用了AsyncMethodBuilderCore的Start方法并传递状态机实例//即<<Main>$>d__0 stateMachine = new <<Main>$>d__0()实例AsyncMethodBuilderCore.Start(ref stateMachine);}//AsyncMethodBuilderCore的Start方法[DebuggerStepThrough]public static void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine{if (stateMachine == null){ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);}//获取当前线程实例Thread currentThread = Thread.CurrentThread;//获取当前执行上下文ExecutionContext executionContext = currentThread._executionContext;//获取当前同步上下文SynchronizationContext synchronizationContext = currentThread._synchronizationContext;try{//调用状态机的MoveNext方法stateMachine.MoveNext();}finally{//执行完MoveNext之后//还原SynchronizationContext同步上下文到当前实例if (synchronizationContext != currentThread._synchronizationContext){currentThread._synchronizationContext = synchronizationContext;}//还原ExecutionContext执行上下文到当前实例ExecutionContext executionContext2 = currentThread._executionContext;if (executionContext != executionContext2){                        //执行完成之后把执行上下文装载到当前线程ExecutionContext.RestoreChangedContextToThread(currentThread, executionContext, executionContext2);}}}

执行完异步任务之后,会判断SynchronizationContext同步上下文环境和ExecutionContext执行上下文环境,保证异步异步之后的可以操作UI线程上的控件,或者异步的后续操作和之前的操作处在相同的执行上线文中。

题外话:ExecutionContext 是一个用于传递状态和环境信息的类,它可以在不同的执行上下文之间传递状态。执行上下文表示代码执行的环境,包括线程、应用程序域、安全上下文和调用上下文等。ExecutionContext 对象包含当前线程上下文的所有信息,如当前线程的安全上下文、逻辑执行上下文、同步上下文和物理执行上下文等。它提供了方法,可以将当前的执行上下文复制到另一个线程中,或者在异步操作之间保存和还原执行上下文。在异步编程中,使用 ExecutionContext 可以确保代码在正确的上下文中运行,并且传递必要的状态和环境信息。

SynchronizationContext 是一个用于同步执行上下文和处理 UI 线程消息循环的抽象类。它可以将回调方法派发到正确的线程中执行,避免了跨线程访问的问题,并提高了应用程序的响应性和可靠性。在异步编程中,可以使用 SynchronizationContext.Current 属性获取当前线程的同步上下文,并使用同步上下文的 Post 或 Send 方法将回调方法派发到正确的线程中执行。

由于调用stateMachine.<>t__builder.Start(ref stateMachine)传递的是new <<Main>$>d__0()实例,所以这里核心就是在调用生成的状态机IAsyncStateMachine实例,即我们上面的<<Main>$>d__0类的MoveNext()方法

void IAsyncStateMachine.MoveNext(){this.MoveNext();}

由上面的代码可知,本质是调用的私有的MoveNext()方法,即会执行我们真实逻辑的那个方法。由于编译器生成的状态机代码的逻辑是大致相同的,所以我们直接来看,我们业务具体落实的代码即<<<Main>$>g__TaskOne|0_0>d状态机类里的,私有的那个MoveNext方法代码

AsyncTaskMethodBuilder<string> <>t__builder;TaskAwaiter<HttpResponseMessage> awaiter2;if (num != 0){if (num == 1){}        //ClassFactory.Client.GetAsyn()方法生成的逻辑awaiter2 = ClassFactory.Client.GetAsync("https://www.cnblogs.com").GetAwaiter();if (!awaiter2.IsCompleted){num = (<>1__state = 0);<>u__1 = awaiter2;<<<Main>$>g__TaskOne|0_0>d stateMachine = this;<>t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine);return;}//同步获取异步结果<>s__4 = awaiter.GetResult();}else{}TaskAwaiter<string> awaiter;//httpResponse.Content.ReadAsStringAsync()方法生成的逻辑awaiter = <httpResponse>5__1.Content.ReadAsStringAsync().GetAwaiter();//判断任务是否完成if (!awaiter.IsCompleted){num = (<>1__state = 1);<>u__2 = awaiter;<<<Main>$>g__TaskOne|0_0>d stateMachine = this;<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);return;}//同步获取异步结果,并将返回值装载result= awaiter.GetResult();<>t__builder.SetResult(result);

当然这里我们省了里面的很多逻辑,为了让结构看起来更清晰一点。
通过上面的它生成的结构来看,我们写代码的时候一个方法里的每个await都会被生成一个TaskAwaiter逻辑,根据当前异步状态IsCompleted判断任务是否完成,来执行下一步操作。如果任务未完成IsCompleted为false则调用AsyncTaskMethodBuilder实例的AwaitUnsafeOnCompleted方法,如果异步已完成则直接获取异步结果,进行下一步。

执行异步任务

通过上面的逻辑我们可以看到,如果异步任务没有完成则调用了AsyncTaskMethodBuilder实例的AwaitUnsafeOnCompleted方法。接下来我们就看下AwaitUnsafeOnCompleted方法的实现

public void AwaitUnsafeOnCompleted<[Nullable(0)] TAwaiter, [Nullable(0)] TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine{//调用AwaitUnsafeOnCompleted方法AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task);}internal static void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref Task<TResult> taskField) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine{//创建IAsyncStateMachineBox实例IAsyncStateMachineBox stateMachineBox = GetStateMachineBox(ref stateMachine, ref taskField);//调用AwaitUnsafeOnCompleted()方法AwaitUnsafeOnCompleted(ref awaiter, stateMachineBox);}internal static void AwaitUnsafeOnCompleted<TAwaiter>(ref TAwaiter awaiter, IAsyncStateMachineBox box) where TAwaiter : ICriticalNotifyCompletion{//判断awaiter实例类型if (default(TAwaiter) != null && awaiter is ITaskAwaiter){//获取TaskAwaiter实例的m_task属性即Task类型TaskAwaiter.UnsafeOnCompletedInternal(Unsafe.As<TAwaiter, TaskAwaiter>(ref awaiter).m_task, box, true);return;}if (default(TAwaiter) != null && awaiter is IConfiguredTaskAwaiter){//与上面逻辑一致m_task属性即Task类型本质他们都在操作Taskref ConfiguredTaskAwaitable.ConfiguredTaskAwaiter reference = ref Unsafe.As<TAwaiter, ConfiguredTaskAwaitable.ConfiguredTaskAwaiter>(ref awaiter);TaskAwaiter.UnsafeOnCompletedInternal(reference.m_task, box, reference.m_continueOnCapturedContext);return;}if (default(TAwaiter) != null && awaiter is IStateMachineBoxAwareAwaiter){try{//调用IStateMachineBoxAwareAwaiter实例的AwaitUnsafeOnCompleted方法((IStateMachineBoxAwareAwaiter)(object)awaiter).AwaitUnsafeOnCompleted(box);return;}catch (Exception exception){System.Threading.Tasks.Task.ThrowAsync(exception, null);return;}}try{//调用ICriticalNotifyCompletion实例的UnsafeOnCompleted方法awaiter.UnsafeOnCompleted(box.MoveNextAction);}catch (Exception exception2){System.Threading.Tasks.Task.ThrowAsync(exception2, null);}}

通过这个方法我们可以看到传递进来的TAwaiter都是ICriticalNotifyCompletion的实现类,所以他们的行为存在一致性,只是具体的实现动作根据不同的实现类型来判断。

我们首先来看一下StateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted()方法,找到一个实现类。因为它的实现类有好几个,比如ConfiguredValueTaskAwaiterValueTaskAwaiterYieldAwaitable等,这里咱们选择有类型的ConfiguredValueTaskAwaiter实现类,看一下AwaitUnsafeOnCompleted方法

void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box){object? obj = _value._obj;Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource);if (obj is Task t){//如果是Task类型的话会调用TaskAwaiter.UnsafeOnCompletedInternal方法,也是上面咱们多次提到的TaskAwaiter.UnsafeOnCompletedInternal(t, box, _value._continueOnCapturedContext);}else if (obj != null){Unsafe.As<IValueTaskSource>(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token,_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);}else{//兜底的方法也是TaskAwaiter.UnsafeOnCompletedInternalTaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value._continueOnCapturedContext);}}

可以看到ConfiguredValueTaskAwaiter.AwaitUnsafeOnCompleted()方法最终也是执行到了TaskAwaiter.UnsafeOnCompletedInternal()方法,这个咱们上面已经多次提到了。接下里咱们再来看一下ICriticalNotifyCompletion.UnsafeOnCompleted()方法里的实现是啥,咱们找到它的一个常用的实现类,也是咱们上面状态机帮咱们生成的TaskAwaiter<>类里的实现

public void UnsafeOnCompleted(Action continuation){TaskAwaiter.OnCompletedInternal(m_task, continuation, true, false);}//TaskAwaiter的OnCompletedInternal方法internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext){ArgumentNullException.ThrowIfNull(continuation, "continuation");if (TplEventSource.Log.IsEnabled() || Task.s_asyncDebuggingEnabled){continuation = OutputWaitEtwEvents(task, continuation);}//这里调用了Task的SetContinuationForAwait方法task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext);}

咱们看到了这里调用的是Task的SetContinuationForAwait方法,上面我们提到的AwaitUnsafeOnCompleted方法里直接调用了TaskAwaiterUnsafeOnCompletedInternal方法,咱们可以来看一下里面的实现

internal static void UnsafeOnCompletedInternal(Task task, IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext){if (TplEventSource.Log.IsEnabled() || Task.s_asyncDebuggingEnabled){//默认情况下我们是没有去监听EventSource发布的时间消息//如果你开启了EventSource日志的监听则会走到这里task.SetContinuationForAwait(OutputWaitEtwEvents(task, stateMachineBox.MoveNextAction), continueOnCapturedContext, false);}else{task.UnsafeSetContinuationForAwait(stateMachineBox, continueOnCapturedContext);}}

因为默认是没有开启EventSource的监听,所以上面的两个TplEventSource.Log.IsEnabled相关的逻辑执行不到,如果代码里坚挺了相关的EventSource则会执行这段逻辑。SetContinuationForAwait方法和UnsafeSetContinuationForAwait方法逻辑是一致的,只是因为如果开启了EventSource的监听会发布事件消息,其中包装了关于异步信息的事件相关。所以我们可以直接来看UnsafeSetContinuationForAwait方法实现

internal void UnsafeSetContinuationForAwait(IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext){if (continueOnCapturedContext){    //winform wpf等ui线程包含同步上下文SynchronizationContext相关的信息//如果存在则直接在SynchronizationContext同步上线文中的Post方法把异步结果在ui线程中完成回调执行SynchronizationContext current = SynchronizationContext.Current;if (current != null && current.GetType() != typeof(SynchronizationContext)){SynchronizationContextAwaitTaskContinuation synchronizationContextAwaitTaskContinuation = new SynchronizationContextAwaitTaskContinuation(current, stateMachineBox.MoveNextAction, false);if (!AddTaskContinuation(synchronizationContextAwaitTaskContinuation, false)){synchronizationContextAwaitTaskContinuation.Run(this, false);}return;}//判断是否包含内部任务调度器,如果不是默认的TaskScheduler.Default调度策略,也就是ThreadPoolTaskScheduler的方式执行MoveNext//则使用TaskSchedulerAwaitTaskContinuation的Run方法执行MoveNextTaskScheduler internalCurrent = TaskScheduler.InternalCurrent;if (internalCurrent != null && internalCurrent != TaskScheduler.Default){TaskSchedulerAwaitTaskContinuation taskSchedulerAwaitTaskContinuation = new TaskSchedulerAwaitTaskContinuation(internalCurrent, stateMachineBox.MoveNextAction, false);if (!AddTaskContinuation(taskSchedulerAwaitTaskContinuation, false)){taskSchedulerAwaitTaskContinuation.Run(this, false);}return;}}//执行兜底逻辑使用线程池执行if (!AddTaskContinuation(stateMachineBox, false)){ThreadPool.UnsafeQueueUserWorkItemInternal(stateMachineBox, true);}}

上面我们提到过IAsyncStateMachineBox实现类包装了IAsyncStateMachine实现类,它的stateMachineBox.MoveNextAction本质是在执行AsyncStateMachine的MoveNext的方法,即我们状态机里的自己的业务逻辑。根据上面的逻辑我们来大致总结一下相关的执行策略

好了上面留下了两个核心的方法,没有展示相关的实现,首先咱们来看下TaskSchedulerAwaitTaskContinuation的Run方法,这个方法适用于存在同步上下文的场景,来看下它的核心逻辑

internal sealed override void Run(Task task, bool canInlineContinuationTask){//判断当前线程同步上下文是否和传递的同步上下文一致,则直接执行,说明当前线程可以直接使用异步结果if (canInlineContinuationTask && m_syncContext == SynchronizationContext.Current){RunCallback(AwaitTaskContinuation.GetInvokeActionCallback(), m_action, ref Task.t_currentTask);return;}    //如果不是同一个同步上下文则执行PostAction委托RunCallback(PostAction, this, ref Task.t_currentTask);}private static void PostAction(object state){//通过传递的state来捕获执行回调的同步上下文,这里使用的SynchronizationContext的非阻塞的Post方法来执行后续逻辑SynchronizationContextAwaitTaskContinuation synchronizationContextAwaitTaskContinuation = (SynchronizationContextAwaitTaskContinuation)state;synchronizationContextAwaitTaskContinuation.m_syncContext.Post(s_postCallback, synchronizationContextAwaitTaskContinuation.m_action);}protected void RunCallback(ContextCallback callback, object state, ref Task currentTask){        //捕获执行上下文,异步执行完成之后在执行上下文中执行后续逻辑ExecutionContext capturedContext = m_capturedContext;if (capturedContext == null){//核心逻辑就是再行上面的委托即AwaitTaskContinuation.GetInvokeActionCallback方法或PostAction方法callback(state);}else{ExecutionContext.RunInternal(capturedContext, callback, state);}}

上面的方法省略了一些逻辑,为了让逻辑看起来更清晰,我们可以看到里面的逻辑,即在同步上下文SynchronizationContext中执行异步的回调的结果。如果当前线程就包含同步上下文则直接执行,如果不是则使用之前传递进来的同步上下文来执行。执行的时候会尝试捕获执行上下文。咱们还说到了如果TaskScheduler调度器不是默认的ThreadPoolTaskScheduler调度器,则使用自定义的TaskScheduler来执行MoveNext方法,来看下里面的核心实现

internal sealed override void Run(Task ignored, bool canInlineContinuationTask){//如果当前的scheduler策略是TaskScheduler.Default即默认的ThreadPoolTaskScheduler//则直接使用默认策略调度任务if (m_scheduler == TaskScheduler.Default){base.Run(ignored, canInlineContinuationTask);return;}//如果不是默认策略则使用,我们定义的TaskSchedulerTask task = CreateTask(delegate(object state){try{((Action)state)();}catch (Exception exception){Task.ThrowAsync(exception, null);}}, m_action, m_scheduler);//这里的m_scheduler指的是自定义的TaskScheduler    bool flag = canInlineContinuationTask && (TaskScheduler.InternalCurrent == m_scheduler || Thread.CurrentThread.IsThreadPoolThread);//或者是task其他形式的策略执行if (flag){TaskContinuation.InlineIfPossibleOrElseQueue(task, false);return;}try{task.ScheduleAndStart(false);}catch (TaskSchedulerException){}}

这个逻辑看起来比较清晰,即根据Task的执行策略TaskScheduler判断如何执行任务,比如默认的ThreadPoolTaskScheduler策略,或其他策略,比如单线程策略或者自定义的等等。
上面的执行过程可以总结为以下两点

线程池和Task关联

如果任务需要执行中,我们总得想办法把结果给相应的Task实例,这样我们才能在执行完成之后把得到对应的执行状态或者执行结果在相关的Task中体现出来,方便我们判断Task是否执行完成或者获取相关的执行结果,在ThreadPoolWorkQueue中有相关的逻辑具体在DispatchWorkItem方法中

private static void DispatchWorkItem(object workItem, Thread currentThread){//判断在线程池中自行的任务书否是Task任务Task task = workItem as Task;if (task != null){task.ExecuteFromThreadPool(currentThread);}else{Unsafe.As<IThreadPoolWorkItem>(workItem).Execute();}}

ThreadPool里的线程执行了Task的ExecuteWithThreadLocal的方法,核心执行方法在Task的ExecuteWithThreadLocal,这样的话执行相关的结果就可以体现在Task实例中,比如Task的IsCompleted属性判断是否执行完成,或者Task<TResult>的GetResultf方法获取结果等等。

Task的FromResult

这里需要注意的是Task.FromResult<TResult>(TResult)这个方法,相信大家经常用到,如果你的执行结果需要包装成Task<TResult>总会用到这个方法。它的意思是创建一个Task<TResult>,并以指定结果成功完成。,也就是Task<TResult>的IsCompleted属性为true,这个结论可以在dotnet api中Task.FromResult(TResult)文档中看到,因为我们只需要把我们已有的结果包装成Task所以不涉及到复杂的执行,这也意味着在生成状态机的时候MoveNext方法里的逻辑判断IsCompleted时候代表任务是直接完成的,会直接通过GetResult()获取到结果,不需要AwaitUnsafeOnCompleted去根据执行策略执行

private void MoveNext(){int num = <>1__state;try{TaskAwaiter<string> awaiter;if (num != 0){awaiter = Task.FromResult("Hello World").GetAwaiter();//这里的IsCompleted会为true不会执行相关的执行策略if (!awaiter.IsCompleted){<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);return;}}else{}<>s__2 = awaiter.GetResult();}catch (Exception exception){}<>t__builder.SetResult();}

“怎么使用c#异步操作async await状态机”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯