详解Node异步I/O机制

参考:
IOCP原理
Philip Roberts: Help, I’m stuck in an event-loop.
谈谈如何提高web服务器并发性能
《深入浅出node.js》by 朴灵

参考书籍介绍

如果想快速了解JS运行机制,快速搞清楚处理回调时究竟是如何运行的,时间不允许,就先只看Philip Roberts: Help, I’m stuck in an event-loop这个20分钟的视频,简单易懂,非常清楚的讲解JS事件循环的机制,这是JS更深入学习的基础, 也是本文必须知道的前言背景。想对线程池的概念有更具体清晰的了解,推荐继续将IOCP原理和谈谈如何提高web服务器并发性能看完,这两篇文章内容不多,后者讲述了线程池技术,前者讲解了线程池是什么,在内核层面创建线程池专门用来放I/O操作完成时的回调函数。朴灵的《深入浅出node.js》则是比较完整系统的对node原理的介绍。本文也是基于本书的第三章而完成的。

Node是什么------ 服务器端的Javascript编程

对于传统的前端工程师而言,我们编写程序,让客户端向服务器发送请求,以及处理客户端的事件。服务端则由后端工程师去搭建web服务器,去处理客户端带来的大量请求。而Node却是全方位的,既可以作为服务器端去处理客户端的并发请求,又能作为客户端向网络中的各个应用进行并发请求(as always)。这篇文章,主要在讲解它作为服务器端的编程。

本文从三个角度分析: 主线程(JS线程),线程池, Event-Loop(事件循环)

主线程:---单线程JS

javascript是单线程的,所以服务器端JS主线程毋庸置疑也是运行在单线程上的
那么在node上,当某行JS行代码要执行一个I/O操作的时候比如打开一个文件,会怎样呢?首先,Javascript会调用node的核心模块(lib/fs.js),核心模块再调用C++内建模块(node_file.cc), C++内建模块判断平台(是unix还是win),然后根据平台进行系统调用,调用nv_fs_open,再这个过程中,创建了一个请求对象FSReqWrap, 将这个请求对象推入到线程池,确定推到线程池之后,good! 至此,JS线程对此I/O代码已执行完毕,接下来可以继续执行JS主线程的下一条代码了!而线程池对这个请求对象的处理安排,接下来都不会影响JS线程。

线程池---多线程I/O

好了,现在有许多个请求对象被推到线程池里来了。那么线程池会怎么样呢?假设线程池里线程数量为100个,而当下有40个线程正在工作,其他60个在待命状态,那么线程池此刻有可用的线程,刚刚被推进线程池的这个对象,线程池会将第41个线程分配给这个请求对象,执行这个对象中的I/O操作,执行完后,将完成的结果放在这个请求对象中,通知Event-Loop调用完成,然后归还本线程也就是第41号线程现在又处于可用状态。结束。

Event Loop

现在对象进入了Event Loop ,事实上可以Event Queu看作一个队列,当请求对象已经通过线程池的一个线程完成了I/O操作并且有了返回结果后,就对应着自己的回调函数(如果有的话,一般都有)。那么在每次一个请求对象完成I/O操作后,将自己对应的回调函数丢进这个队列,现在这个队列已经按丢进来的先后顺序,排列好了许多回调函数。现在要干嘛呢?等。。。等到JS主线程执行完毕后,开始一条条将本队列中的函数推到主进程执行。结束。总起起来,事件循环事实上是对I/O操作的回调函数的集合做循环,也可以说是对已完成I/O操作的请求对象们的集合,对它们做循环,取请求对象完成I/O操作后的结果然后它的执行回调函数,执行完后,再对队列中下一个请求对象做同样的事。

详解Node异步I/O机制_第1张图片
Paste_Image.png

总结

从以上描述中,可以提取node异步I/O的几个关键字:单线程,事件循环,I/O线程池。在Node中,除了Javascript是单线程外,Node自身其实是多线程的。那么除了用户代码无法并行执行外,所有的I/O则是可以并行起来的。

你可能感兴趣的:(详解Node异步I/O机制)