目录
异步的底层实现方式有哪些?
1 多线程
AJAX与多线程
2 上下文切换
DMA的基本定义
异步的底层实现方式有哪些?
1 多线程
什么叫多线程?
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。
那么实现怎么使用多线程来实现异步?
我们可以参照AJAX异步来理解。
AJAX与多线程
首先明确一点:Ajax是单线程的,因为JavaScript是单线程的,Ajax属于JavaScript范畴,因此Ajax是单线程的。
之所以我们可以利用Ajax做到异步,因为浏览器使用了多线程,同时,服务端也使用多线程处理请求。
如图展示了浏览器是多进程的。
如图,打开edge浏览器就会有很多线程。如果是发送AJAX请求那么就会有一个子进程用于发送请求。所以就实现了AJAX的异步请求了。
2 上下文切换
什么叫上下文切换?
上下文切换指的是内核(操作系统的核心)在CPU上对进程或者线程进行切换。上下文切换过程中的信息被保存在进程控制块(PCB-Process Control Block)中。PCB又被称作切换帧(SwitchFrame)。上下文切换的信息会一直被保存在CPU的内存中,直到被再次使用。
上下文的切换流程如下
(1)挂起一个进程,将这个进程在CPU中的状态(上下文信息)存储于内存的PCB中。
(2)在PCB中检索下一个进程的上下文并将其在CPU的寄存器中恢复。
(3)跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行)并恢复该进程。
时间片轮转方式使多个任务在同一CPU上的执行有了可能,具体过程如图2所示。
下面贴出百度百科上的引起线程上下文切换的原因
引起线程上下文切换的原因如下
(1)当前正在执行的任务完成,系统的CPU正常调度下一个任务。
(2)当前正在执行的任务遇到I/O等阻塞操作,调度器挂起此任务,继续调度下一个任务。
(3)多个任务并发抢占锁资源,当前任务没有抢到锁资源,被调度器挂起,继续调度下一个任务。
(4)用户的代码挂起当前任务,比如线程执行yield()方法,让出CPU。
(5)硬件中断。
值得注意的是第2条原因,当遇到I/O时会去挂起当前的线程,我们可以联想到,node.js是底层异步IO的实现原理,肯定与这个脱不了干系。
值得注意的是你真的了解IO吗?
磁盘IO是怎么读到程序中的,为什么使用此种方式不需要而外创建新的线程?
首先
DMA的基本定义
DMA,全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。
现在有一个线程我们把它命名为t1
它需要执行两个任务
第1个任务是从磁盘中读取一段视频
第2个任务中是从磁盘中读取一大段文字
假如我们使用上下文切换的方式实现异步那么它的执行流程应该是这样的:-》
首先线程t1得到CPU之后初始化视频传输任务,底层就是CPU初始化了一个传输动作这个动作是通过DMA控制器来实现的具体可看下面DMA的定义,初始化完成之后现成不会等待接着初始化读取文字的任务,全部初始化完成之后t1闲置,接着通过回调函数获取到视频读取的结果和文字读取的结果这样的一个过程就是异步。
所以说有两个关键点,一个是DMA的管道传输机制
一个是回调函数的应用
这么说他是不是与上下文切换没有关系了呢?别急咱们举的这个是读io的情况,假如不是读io的情况那是什么情况呢?假设现在有一个线程t2, t2需要完成两个计算任务分别是a1和a2,如果使用上下文切换实现异步的话,那么执行流程的话就是t2先走到 a1任务的起始位置,然后启动a1任务,在执行若干时间之后将a1任务挂起,在运行到A2任务的起始位置执行A2任务,然后执行若干秒之后将A2任务挂起执行a一任务彼此往复相互竞争,如此以来也是异步。
但是这时候一部的缺点就显示出来了,频繁的上下文切换会损耗大量的性能,此时异步的性能比同步更差。
所以一步大多是使用在读io的情况下比如说网络io和磁盘io,因为他们两者都是使用的管道技术。
而不是使用上下文轮转。其他在多线程语言中异步的实现方式更多是使用多线程来支撑。