关于node.js内部异步I/O机制的困惑

Posted

技术标签:

【中文标题】关于node.js内部异步I/O机制的困惑【英文标题】:Confusion about node.js internal asynchronous I/O mechanism 【发布时间】:2013-03-09 17:23:12 【问题描述】:
    我了解到 node.js 在内部使用 libeio 在 *nix 平台上使用线程池执行异步 file I/O,对吗? 异步网络 I/O 怎么样?它是由libev完成的吗?还有线程池吗? 如果里面有线程池,怎么会比传统的一个请求一个线程的模型更高效呢?每个 I/O 请求一个线程吗? Windows 的机制是什么?我知道是 IOCP 做的,还有内核级别的线程池,对吧? 为什么linux还没有像windows IOCP这样原生的完全AIO机制?以后会有吗?

根据长昌的回答更新:

    我在source code@changchang 给出的快速查看,发现默认线程池大小可以通过UV_THREADPOOL_SIZE 来重置,我想知道在什么情况下会使用这个? 我也发现getaddrinfo使用这个线程池,除了fs还有吗?如果所有同步作业都在这个线程池中完成,那么默认大小“4”是否足够? 据我现在的理解,node.js 进程中将有 6 个基本线程:1 个 V8 线程(事件循环,用户 javascript 代码运行的地方)、1 个 libuv 事件循环和 4 个线程池,对吗?

    我怎样才能在我的 shell(Ubuntu)中看到这些线程?我使用 ps -eLf | grep 节点 | grep -v grep 只看到了两个:

    root 16148 7492 16148 0 2 20:43 pts/26 00:00:00 ./bin/node /home/aaron/workspace/test.js 根 16148 7492 16149 0 2 20:43 pts/26 00:00:00 ./bin/node /home/aaron/workspace/test.js

【问题讨论】:

见这里***.com/questions/10680601/nodejs-event-loop node.js 实际上使用libuv 为所有支持的平台抽象异步IO @user568109 我已经读过,但无法从中得到直接的答案,实际上,不清楚的表达更让我困惑。它提到 libeio '异步执行输入输出'包括套接字,我对此表示怀疑。我从某个地方了解到这一点:因为不能在常规文件上使用 epoll,所以这里有 libeio 来使用线程执行 aio。 @simfoo 是的,我知道 libuv,我想知道它下面的机制,包括 *nix 和 windows。 【参考方案1】:

    首先,libuv 已从中删除了 libeio。但正如您所提到的,它确实使用像 libeio 这样的线程池执行异步文件 I/O。

    libuv 也会删除 libev。它基于epollkqueueIOCP等不同平台的异步I/O接口进行异步网络I/O,没有线程池。有一个事件循环在uv 的主线程上运行,它轮询 I/O 事件并对其进行处理。

    libuv里面的线程池是一个固定大小的线程池(4 in uinx like system)。它执行任务队列角色,并通过在请求增加时无限生成线程来避免系统资源的耗尽。

【讨论】:

坦克很多,很多资源都过时了,你刚刚救了我! @AaronWang 如果它回答了你的问题,你应该接受它。 首先:libuv [...] 执行异步网络 I/O [...] 没有线程池。后来:libuv 中的线程池[...]。这对我来说似乎是矛盾的。 4 不是一个很小的数字,尤其是对于 io 绑定的任务。节点是否允许更改池大小? ^ 是的,通过 UV_THREADPOOL_SIZE【参考方案2】:

Uptil 0.6 版节点使用libev 运行事件循环,libeio 用于异步 I/O,(Unix 后端在这两个库上占很大比重)。但是libuv 已经开始替换version 0.8 中的libevlibeio。它执行、维护和管理事件池中的所有 io 和事件。 libuv是跨平台异步IO库的选择。

    是的,直到节点 0.6,在 0.8 中已弃用并使用线程池

    是的,但是libev 不使用线程池。见here

    澄清:根据我发布的question 中的link,libeio 确实支持所有处理 I/O(包括套接字)的 POSIX 函数。但节点作者决定仅将其用于异步文件 I/O,并将libev 用于网络 I/O。我不知道你是从哪里听说的,但你可以在常规文件上使用 epoll。

    libev 使用事件循环,所以这里没有问题。

    是的IOCP 在 Windows 中处理异步 I/O,内核确实使用线程池。 新的 linux 内核在新的 BSD 内核中有 epoll、kqueue。 libevlibeio 用于 linux 环境,为所有内核提供事件循环/异步 IO(支持 select、poll、epoll、kqueue)。

更新问题:

    不太了解libuv 也许够了(不知道)

    这是我在 Windows 8 上的发现,通过 Process Explorer 进行了检查。显示了一个节点应用程序进程的 4 个线程、1 个 DLL、1 个文件和 1 个部分(共 7 个条目)。

    ps -eLf 确实显示了所有线程和进程,也许您对其进行了过度过滤,只需查找节点进程 pid,例如 ps -eLf | grep x,其中 x 是节点进程的 pid。

【讨论】:

以上是关于关于node.js内部异步I/O机制的困惑的主要内容,如果未能解决你的问题,请参考以下文章

node.js的异步编程

Node.js中的异步I/O是如何进行的?

为啥在 Node.js 中阻塞文件 I/O 时异步性能更差?

《node.js实战》第一章读后感

JavaScript 中的事件循环和 Node.js 中的异步非阻塞 I/O 有啥区别?

玩转Node.js - 04. 第一个异步 I/O!