[node设计理念] 单线程异步I/O

2021-02-18  本文已影响0人  _royalpioneer

内容

node的单线程异步io模型是这样设计的:

(1)执行异步方法,将异步的任务交给内核,不带数据返回;

(2)继续执行其他操作

(3)事件循环拿到异步操作完成的信号或者事件后,执行异步方法中的回调函数

如图

image.png

这个设计是怎么实现的呢? 需要几个帮手,事件循环,观察者,请求对象,线程池,以下拿 fs.open 举例子:

fs.open('<directory>', 'r+', (err, fd) =>  {
  // ...
});

我们使用fs.open, 即调用了lib中fs.js, 然后fs.js调用了c++核心模块node_file.cc, 然后判断判断平台来采取不同的操作

image.png

判断好平台后,node会创建一个请求对象,请求对象会保存当前所有的状态和回调函数,当前场景下的请求对象是 FSReqWrap。

请求对象会送入IO线程池等待执行,执行完毕后会将执行结果存放在请求对象的result属性上,然后通知操作系统当前对象操作已完成,并归还线程给线程池。

事件循环中的IO观察者会在每轮tick中检查线程池中是否有执行完成的请求,有的话,取出对应的请求对象的回调函数,并取出result作为参数(这里对应的是err 或 fd),然后执行。

至此,一个异步IO就完成了。

image.png

写在后面

首先来理解下为什么node要采用单线程异步io。

如果是多线程,会面临各线程状态同步,锁的问题。如果是单线程同步阻塞,在多并发的情况下等待的时间会很长,而采用上述设计模型的单线程异步io能很好的规避所提的这两个问题。

另外,javascript在服务器端编程领域上没有历史包袱,加上前端开发者对异步编程都比较熟悉,所以node就采用了单线程异步io的模型。

其次,node是多线程的,单线程是指js是单线程执行的。

node是由一个js执行线程和多个阻塞线程组成的线程池构成的。io异步中的一个重要帮手就是事件循环,事件循环是典型的生产者消费者模型,在windows下基于IOCP创建,在Linux下基于多线程创建(libuv自行实现)。

参考链接

上一篇下一篇

猜你喜欢

热点阅读