浅谈Async和Await如何简化异步编程(几个实例让你彻底明白)

2019-12-30 15:22:57于海丽

如果你看过我的迭代器专题的话,相信你肯定可以联想到该结构体就是一个迭代器的一个实现,其主要方法就是MoveNext方法。

从上面的代码的注释应该可以帮助我们解决在第一步提到的第一个问题,即<btnClick_Click>d__0是什么类型,下面就分析下第二个问题,从<btnClick_Click>d__0结构体的代码中可以发现<>t__builder的类型是AsyncVoidMethodBuilder类型,下面就看看它的Start方法的解释——运行关联状态机的生成器,即调用该方法就可以开始运行状态机,运行状态机指的就是执行MoveNext方法(MoveNext方法中有我们源码中所有代码,这样就把编译器生成的Click方法与我们的源码关联起来了)。

从上面代码注释中可以发现,当该MoveNext被调用时会立即还回到GUI线程中,同时也有这样的疑问——刚开始调用MoveNext方法时,任务肯定是还没有被完成的,但是我们输出我们源码中的代码,必须等待任务完成(因为任务完成才能调转到Label_007A中的代码),此时我们应该需要回调MoveNext方法来检查任务是否完成,(就如迭代器中的,我们需要使用foreach语句一直调用MoveNext方法),然而我们在代码却没有找到回调的任何代码啊?

对于这个疑问,回调MoveNext方法肯定是存在的,只是首次看上面代码的朋友还没有找到类似的语句而已,上面代码注释中我提到了一个问题——这个代码是做什么用的呢?让我们带着问题看下面的分析,其实注释下面的代码就是起到回调MoveNext方法的作用,AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted<TAwaiter, TStateMachine> 方法就是调度状态机去执行MoveNext方法,从而也就解决了回调MoveNext的疑问了。

相信大家从上面的解释中可以找到源码与编译器代码之间的对应关系了吧, 但是我在分析完上面的之后,又有一个疑问——当任务完成时,是如何退出MoveNext方法的呢?总不能让其一直回调吧,从上面的代码的注释可以看出,当任务执行完成之后,会把<>1__state设置为0,当下次再回调MoveNext方法时就会直接退出方法,然而任务没完成之前,同样也会把<>1__state设置为0,但是Switch部分后面的代码又把<>1__state设置为-1,这样就保证了在任务没完成之前,MoveNext方法可以被重复回调,当任务完成之后,<>1__state设置为-1的代码将不会执行,而是调转到Label_007A部分。

经过上面的分析之后,相信大家也可以耍出一套还我漂漂拳去分析异步方法AccessWebAsync(),其分析思路是和btnClick_Click的分析思路是一样的.这里就不重复啰嗦了。

分析完之后,下面再分享下几个关于async和await常问的问题

问题一:是不是写了async关键字的方法就代表该方法是异步方法,不会堵塞线程呢?