深入浅出nodejs(异步I/O)

2019-03-17  本文已影响0人  fangPeng__

异步IO实现现状

堵塞I/O造成CPU的等待浪费,非堵塞I/O是需要轮询去确认是否完成数据获取,让CPU处理状态判断,这是对cpu资源的浪费。

轮询的演进,以减少I/O状态判断的CPU损耗

理想的非堵塞异步I/O

应用程序发起非堵塞调用,无需遍历或者唤醒,可以直接处理下一个任务,只需要在I/O完成后通过信号或者回掉将数据传递给应用程序

现实中的异步I/O

线程池模拟异步I/O。

WechatIMG3.jpeg
通过让部分线程用轮询技术进行数据的获取,让一个线程进行计算处理,通过线程间的通信将I/O得到的数据进行传递
node的上一层libuv 即用此实现,并进行来平台的兼容

node 的异步I/O

事件循环

进程启动时,Node会创建一个类似while(true)的循环,判断是否有事件需要处理,若有,取出事件并执行回调函数。


WechatIMG4111.jpeg

观察者

在Tick 的过程中,引入观察者的概念,用来判断是否有事件需要处理。一个事件循环中有一个或多个观察者,一个观察者里可能有多个事件

请求对象

WechatIMG5.jpeg

从javaScript 调用node的核心模块,核心模块调用C++的内建模块,内建模块通过libux 进行系统调用,这是node的经典调用方式。
javaScript 传入的参数和当前的方法都会被封装到这个请求对象中去,回调函数被设置到这个对象的oncomplete_sym属性上

执行回调

组装好请求对象、送入I/O线程池等待执行完成异步I/O的第一部分,回调通知是第二部分,线程池中的I/O操作调用完毕之后,会把结果存储在req->result属性上,然后调用PostQueuedCompletionStatus()通知IOCP,告知当前对象操作已经完成,
PostQueuedCompletionStatus()方法的作用是向IOCP提交执行状态,并将线程池归还线程,通过这个方法提交状态可GetQueuedCompletionStatus提取,这个工程中动用了事件循环的I/O观察者,每次Tick的执行中,都会调用IOCP相关的GetQueuedCompletionStatus方法检查线程池中是否有执行完毕的请求,如果有就将请求对象加入I/O观察者队列中,然后当作事件处理,I/O观察者调用回调函数就是取出请求对象的result属性作为参数,取出oncomplete_sym作为方法,然后执行。


WechatIMG6.jpeg

非I/O的异步API

setTimeout()、setInterval()、setImmediate()、process.nextTick()

它们与异步I/O相似,只不过不需要I/O线程池的参与,每次Tick时。会检查是否满足条件,如果满足就形成一个事件,所有事件都会被事件循环按顺序排队处理,直到所有队列为空。

在nodejs中有多个观察者队列,不同类型的事件在它们自己的队列中排队。在处理一个类型的队列之后,在进入到下一个队列之前,事件循环将处理两个中间队列(宏任务队列和微任务队列),直到中间队列为空。

执行顺序

1、先执行微任务队列,并且一次执行完。
2、在执行宏任务一个宏任务如果发现还有微任务继续执行微任务

上一篇 下一篇

猜你喜欢

热点阅读