对于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的过程的更多相关文章

  1. NodeJS中的异步I/O、事件驱动

    nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...

  2. AJAX异步请求原理和过程

    AJAX 指异步 JavaScript 及 XML(Asynchronous JavaScript And XML),它不是一种新的编程语言,而是一种使用现有标准的新方法. AJAX 基于 JavaS ...

  3. nodejs之路-[0]安装及简易配置

    题外话: 之前写过ubuntu下编译nodejs- 传送门:Ubuntu15.04编译安装nodejsV0.12.3 只是如今基本在win下做开发了-. 就以这篇帖子为开头,作为我踏上nodejs之路 ...

  4. nodejs 中的异步之殇

    nodejs 中的异步之殇 终于再次回到 nodejs 异步中,以前我以为异步在我写的文章中,已经写完了,现在才发现,还是有很多的地方没有想清楚,下面来一一说明. 模块同步与连接异步 大家应该,经常使 ...

  5. Nodejs之路:非I/O的异步API

    本篇主要介绍setTimeout,setInterval,setImmediate和process.nextTick. 1,定时器 Node中的定时器和浏览器中用法一致.区别在于:在Node中,执行到 ...

  6. NodeJS学习之异步编程

    NodeJS -- 异步编程 NodeJS最大的卖点--事件机制和异步IO,对开发者并不透明 代码设计模式 异步编程有很多特有的代码设计模式,为了实现同样的功能,使用同步方式和异步方式编写代码会有很大 ...

  7. 深入理解nodejs中的异步编程

    目录 简介 同步异步和阻塞非阻塞 javascript中的回调 回调函数的错误处理 回调地狱 ES6中的Promise 什么是Promise Promise的特点 Promise的优点 Promise ...

  8. Nodejs爬虫进阶=>异步并发控制

    之前写了个现在看来很不完美的小爬虫,很多地方没有处理好,比如说在知乎点开一个问题的时候,它的所有回答并不是全部加载好了的,当你拉到回答的尾部时,点击加载更多,回答才会再加载一部分,所以说如果直接发送一 ...

  9. 如何优雅的处理Nodejs中的异步回调

    前言 Nodejs最大的亮点就在于事件驱动, 非阻塞I/O 模型,这使得Nodejs具有很强的并发处理能力,非常适合编写网络应用.在Nodejs中大部分的I/O操作几乎都是异步的,也就是我们处理I/O ...

随机推荐

  1. [UE4]手柄显示射线

    1.实时动态从手柄处发出一条射线 2.可以在Event Tick事件中使用LineTraceByChannel方法.注意Draw Debug Type(射线生命周期)要选择For One Frame. ...

  2. 4th Dec 2018

    两个人都觉得自己没错,或者对方都把错误归结于另外一方,总会盯着对方的不足,无限放大:谁都不肯先放下兵器,亦或害怕自己放下了兵器,对方又拿起了盾.这就好像双方在同一时间拉扯一根皮筋,拉扯的越长,张力越大 ...

  3. 换上 SansForgetica-Regular 字体,增加记忆能力

    最近澳大利亚的RMIT(皇家墨尔本理工大学) 搞出来这么个字体,号称能增强记忆,原理是通过难以识别的字体,让人提起精神去识别,从而记忆更深刻. 果断弄了个试试. 安装过程: 下载字体文件 点这里去下载 ...

  4. Servlet的几个关键知识点

    1.ServletConfig ServletConfig是Servlet的配置文件.对应于web.xml中的<servlet></servlet>标签.ServletConf ...

  5. JavaScript获取、修改CSS样式合辑

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Web缓存机制

    Web 缓存的出现主要是为了弥补cookie带来的一些局限,当数据严格控制在客户端时,可以不用通过HTTP来持续得将数据发给服务器. 主要使用比较多的就是sessionStorage和localSto ...

  7. ssh服务器配置

    使用如下终端命令可以在 Linux 主机中安装 ssh服务器sudo apt-get install openssh-server lin@lin-machine:~$ sudo apt-get in ...

  8. Apache Struts2高危漏洞(S2-057CVE-2018-11776)

    花了两天时间,特此记录 一:背景: 2018年8月22日,Apache Strust2发布最新安全公告,Apache Struts2存在远程代码执行的高危漏洞. 二:漏洞产生原理: 1.需要知道对应跳 ...

  9. fastjson中对象转化为字符串时过滤某字段

    fastjson中对象转化为字符串时过滤某字段,有两种方法: 一.在该字符定义上方添加"@JSONField(serialize=false)"注解: 二.调用含有Property ...

  10. Java语法 [HelloWorld]

    程序代码: public class lqx {// AAAAANBBBBCKJKSLJIOQL/*请手打哦!*/ public static void main (String[] args) { ...