print(‘age $onValue’);
});
协程
如果想要了解async
、await
的原理,就要先了解协程的概念,async
、await
本质上就是协程的一种语法糖。协程,也叫作coroutine
,是一种比线程更小的单元。如果从单元大小来说,基本可以理解为进程->线程->协程。
任务调度
在弄懂协程之前,首先要明白并发和并行的概念,并发指的是由系统来管理多个IO的切换,并交由CPU去处理。并行指的是多核CPU在同一时间里执行多个任务。
并发的实现由非阻塞操作+事件通知来完成,事件通知也叫做“中断”。操作过程分为两种,一种是CPU对IO进行操作,在操作完成后发起中断告诉IO操作完成。另一种是IO发起中断,告诉CPU可以进行操作。
线程本质上也是依赖于中断来进行调度的,线程还有一种叫做“阻塞式中断”,就是在执行IO操作时将线程阻塞,等待执行完成后再继续执行。但线程的消耗是很大的,并不适合大量并发操作的处理,而通过单线程并发可以进行大量并发操作。当多核CPU出现后,单个线程就无法很好的利用多核CPU的优势了,所以又引入了线程池的概念,通过线程池来管理大量线程。
协程
在程序执行过程中,离开当前的调用位置有两种方式,继续调用其他函数和return
返回离开当前函数。但是执行return
时,当前函数在调用栈中的局部变量、形参等状态则会被销毁。
协程分为无线协程和有线协程,无线协程在离开当前调用位置时,会将当前变量放在堆区,当再次回到当前位置时,还会继续从堆区中获取到变量。所以,一般在执行当前函数时就会将变量直接分配到堆区,而async
、await
就属于无线协程的一种。有线协程则会将变量继续保存在栈区,在回到指针指向的离开位置时,会继续从栈中取出调用。
async、await原理
以async
、await
为例,协程在执行时,执行到async
则表示进入一个协程,会同步执行async
的代码块。async
的代码块本质上也相当于一个函数,并且有自己的上下文环境。当执行到await
时,则表示有任务需要等待,CPU则去调度执行其他IO,也就是后面的代码或其他协程代码。过一段时间CPU就会轮训一次,看某个协程是否任务已经处理完成,有返回结果可以被继续执行,如果可以被继续执行的话,则会沿着上次离开时指针指向的位置继续执行,也就是await
标志的位置。
由于并没有开启新的线程,只是进行IO中断改变CPU调度,所以网络请求这样的异步操作可以使用async
、await
,但如果是执行大量耗时同步操作的话,应该使用isolate
开辟新的线程去执行。
如果用协程和iOS的dispatch_async
进行对比,可以发现二者是比较相似的。从结构定义来看,协程需要将当前await
的代码块相关的变量进行存储,dispatch_async
也可以通过block
来实现临时变量的存储能力。
我之前还在想一个问题,苹果为什么不引入协程的特性呢?后来想了一下,await
和dispatch_async
都可以简单理解为异步操作,OC的线程是基于Runloop
实现的,Dart
本质上也是有事件循环的,而且二者都有自己的事件队列,只是队列数量和分类不同。
我觉得当执行到await
时,保存当前的上下文,并将当前位置标记为待处理任务,用一个指针指向当前位置,并将待处理任务放入当前isolate
的队列中。在每个事件循环时都去询问这个任务,如果需要进行处理,就