Nodejs之路:异步I/O的过程
对于Node中的异步I/O调用,从发出调用到回调执行,看起来像普通的js异步,但是流程却和普通js那些消息队列完全不同,整个过程经历了哪些?
下面以Windows平台下为例:
一,异步调用第一阶段:
1,首先JavaScript调用Node的核心模块,核心模块再调用C++内建模块,内建模块通过libuv进行系统调用。(这里的libuv是抽象封装层,使得平台兼容性的判断都由这一层来实现,并保证上层的Node与下层的自定义线程及IOCP之间互相独立。Node在编译期间会判断平台条件,选择性编译unix目录或是win目录下的源文件到目标程序中。)
内建模块调用过程中,会创建一个FSReqWrap请求对象,从JavaScript层传入的参数和当前方法都被封装在这个请求对象中,而回调函数则被设置在这个请求对象的oncomplete_sym属性上。
2,对象包装完毕后,在Windows下,则调用QueueUserWorkItem()方法将这个FSReqWrap请求对象推入线程池中等待执行,该方法使用代码如下:
QueueUserWorkItem( &uv_fs_thread_proc, req, WT_EXECUTEDEFAULT )
这个方法接收三个参数,第一个是将要执行的方法的引用,这里的例子是uv_fs_thread_proc,这里实际上就是要执行的I/O操作实际对应的方法,第二个是执行这个方法运行时所需的参数,第三个是执行的标志。
3,当线程池中有可用线程时,就会调用这个引用方法,这里就是uv_fs_thread_proc()方法,这个方法会根据传入参数的类型调用相应的底层函数。
至此,JavaScript调用立即返回,可以继续执行当前任务的后续任务,当前的I/O操作在线程池中等待执行,不会影响到JavaScript线程的后续执行,如此达到异步的目的。
第一部分关键就是这个请求对象,它是异步I/O过程中重要的中间产物,所有的状态都保存在这个对象中,包括送入线程池等待执行以及I/O操作完毕后的回调。
二,第二阶段
1,线程池中的I/O操作调用完毕之后,会将获取的结果存储在req -> result属性上,然后调用PostQueueCompletionStatus()通知IOCP,告知当前对象操作完成。这个PostQueueCompletionStatus方法的作用是向IOCP提交执行状态,并将线程归还线程池。
2,而提交的这个执行状态,可以通过GetQueueCompletionStatus()获取,很好理解,一个post,一个get,而谁来调用这个get方法呢?就是事件循环中的I/O观察者。每次事件循环,它会调用IOCP相关的GetQueueCompletionStatus方法检查线程池中是否有执行完的请求,如果存在,会将请求对象加入到I/O观察者的队列中,然后将其当做事件处理。
3,I/O观察者回调函数的行为就是取出请求对象的result属性作为参数,取出oncomplete_sym属性作为方法,然后调用执行,以此达到调用回调函数的目的。
以上就是完整的从开始调用异步I/O,到执行完毕后调用回调函数的整个过程。
总结:
上面的一些对象名、函数名、属性名比较多,且长,这里大概讲一下,不需要死记这些名词。
异步调用发起,把异步I/O、参数、状态等,以及最重要的回调函数封装进一个请求对象,然后将这个请求对象推入线程池等待执行,如果线程池中有可用的线程,就执行请求对象中的I/O操作实际对应的方法,参数也从里面拿,执行完成后,将结果放在请求对象中,然后调用一个postbalabala方法,通知IOCP调用完成了并且归还线程。而事件循环的过程中,I/O观察者会不断地轮询是否有可用的请求对象,具体方式就是调用一个getbalabala方法来查看执行状态,如果有了就表示有I/O任务执行完成了,那么就调用请求对象里的回调函数和执行结果,然后继续轮询。
所谓的事件驱动,其实本质上面已经介绍过了,即通过主循环加事件触发的方式来运行程序。简单来说,当进来一个新的请求的时,请求将会被压入队列中,然后通过一个循环来检测队列中的事件状态变化,如果检测到有状态变化的事件,那么就执行该事件对应的处理代码,一般都是回调函数。这个请求就是上面提到的请求对象。
====================
2019.03.07
同步和异步看主线程,阻塞和非阻塞看I/O线程


以上两张图截选自朴灵老师的深入浅出nodejs,图一是整个异步IO的流程,图二也是异步IO,只是少一个事件循环的流程图;
我们刚刚说同步异步看主线程,就是图二里的异步调用那个模块和图一里的主线程;但是我们要注意,node始终是单线程,也就是说在每一个线程上都是按顺序执行。当我们有异步调用发生时,比如有100个异步调用,也是完全按顺序执行,只不过每次调用,会很快的结束(三个步骤:封装请求对象,设置参数和回调,推入线程池),然后开始下一次调用(继续三步骤),如果是同步的,那么下一次调用一定要等上一次调用有结果返回了,才会进行。就像我们之前一篇随笔说的,异步和同步的区别在于消息通知是主动还是被动,是主动去关心还是根本不关心。
那我们再来看阻塞和非阻塞,当线程池有可用的线程时,(待续)
end
Nodejs之路:异步I/O的过程的更多相关文章
- NodeJS中的异步I/O、事件驱动
nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...
- AJAX异步请求原理和过程
AJAX 指异步 JavaScript 及 XML(Asynchronous JavaScript And XML),它不是一种新的编程语言,而是一种使用现有标准的新方法. AJAX 基于 JavaS ...
- nodejs之路-[0]安装及简易配置
题外话: 之前写过ubuntu下编译nodejs- 传送门:Ubuntu15.04编译安装nodejsV0.12.3 只是如今基本在win下做开发了-. 就以这篇帖子为开头,作为我踏上nodejs之路 ...
- nodejs 中的异步之殇
nodejs 中的异步之殇 终于再次回到 nodejs 异步中,以前我以为异步在我写的文章中,已经写完了,现在才发现,还是有很多的地方没有想清楚,下面来一一说明. 模块同步与连接异步 大家应该,经常使 ...
- Nodejs之路:非I/O的异步API
本篇主要介绍setTimeout,setInterval,setImmediate和process.nextTick. 1,定时器 Node中的定时器和浏览器中用法一致.区别在于:在Node中,执行到 ...
- NodeJS学习之异步编程
NodeJS -- 异步编程 NodeJS最大的卖点--事件机制和异步IO,对开发者并不透明 代码设计模式 异步编程有很多特有的代码设计模式,为了实现同样的功能,使用同步方式和异步方式编写代码会有很大 ...
- 深入理解nodejs中的异步编程
目录 简介 同步异步和阻塞非阻塞 javascript中的回调 回调函数的错误处理 回调地狱 ES6中的Promise 什么是Promise Promise的特点 Promise的优点 Promise ...
- Nodejs爬虫进阶=>异步并发控制
之前写了个现在看来很不完美的小爬虫,很多地方没有处理好,比如说在知乎点开一个问题的时候,它的所有回答并不是全部加载好了的,当你拉到回答的尾部时,点击加载更多,回答才会再加载一部分,所以说如果直接发送一 ...
- 如何优雅的处理Nodejs中的异步回调
前言 Nodejs最大的亮点就在于事件驱动, 非阻塞I/O 模型,这使得Nodejs具有很强的并发处理能力,非常适合编写网络应用.在Nodejs中大部分的I/O操作几乎都是异步的,也就是我们处理I/O ...
随机推荐
- Ali流量控制中间件Sentinel
原文链接: https://blog.csdn.net/u012190514/article/details/81383698 Sentinel 是什么 随着微服务的流行,服务和服务之间的稳定性变得越 ...
- 一个简单的通讯服务框架(大家发表意见一起研究)JAVA版本
最近研究下java语言,根据一般使用的情况,写了个连接通讯服务的框架: 框架结构 C-Manager-S; 把所有通讯内容抽取成三个方法接口:GetData,SetData,带返还的Get; 所有数据 ...
- java中随机二维数组中寻找最大值并输出坐标
public static void main(String[] args) { int x=0; int y=0; int a[][]=new int[5][5]; int max=-Integer ...
- mongo官方企业版安装及数据库授权使用
通过安装.deb包的方式,系统是Ubuntu 16.04 1. Import the public key used by the package management system.(导入包管理系统 ...
- 在consul上注册web服务
1. 创建web服务 IDEA->File->New->Project->Empty Project,project name取名provider,点击finish 2. 创建 ...
- openstack网络
OpenStack中neutron的2种ip.3种管理模式 Nova有固定IP和浮动IP的概念.固定IP被分发到创建的实例不再改变,浮动IP是一些可以和实例动态绑定和释放的IP地址. Nova支持3种 ...
- PHPsocket、CURL、File_get_contents采集
1.socket采集.采用最底层的,它只是建立一个长连接,然后我们自己构造http协议字符串去发送请求.例如想获取这个页面内容(http://tv.youku.com/?spm=a2hww.20023 ...
- python TKinter部分记录
http://blog.shouji-zhushou.com/python-gui-tkinter-grid%E7%BD%91%E6%A0%BC%E5%87%A0%E4%BD%95%E5%B8%83% ...
- leetcode78
本题是回溯法的基本应用,深度优先遍历,使用递归实现. class Solution { public: ]; vector<vector<int>> R; int n; //t ...
- leetcode101
/** * Definition for a binary tree node. * public class TreeNode { * public int val; * public TreeNo ...