Nodejs 是如何做 i/o 的?

How does the Nodejs do i/o under the hood?

我知道nodejs使用libuv提供的线程池做并发工作。我读到 nodejs 只需要第 os 个线程之一来完成所有 i/o 绑定活动

那么非阻塞文件操作是如何发生的?

如果我遍历一个包含 100 个文件的文件夹并使用 readFile() 打开所有文件,在节点、磁盘和 os 之间实际上会发生什么?

如果在其他一些多线程和阻塞语言中执行相同的操作将导致线程等待 i/o 完成,那么谁在等待 i/o 完成 nodejs? ,尤其是同时发生多个文件操作时?

谢谢!

nodejs中的文件IO使用了线程池。默认情况下,池中有 4 个线程。

当某些 Javascript 在 nodejs 中调用诸如 fs.open() 之类的文件操作时,该调用将被路由到 nodejs 实现中的 libuv 库中的某些本机代码。该代码将特定文件操作添加到等待 OS 线程的项目队列中。如果 OS 线程立即可用,则该 OS 线程被赋予执行文件操作的任务,然后 returns 返回到 returns 的原始 libuv 函数 returns原始 Javascript 和 nodejs 继续 运行 其他 Javascript.

然后,稍后线程完成文件操作并得到结果。它向 nodejs 事件队列中插入一个事件,其中包含完成的结果和原始文件操作传递的原始回调。

当 nodejs 完成执行任何其他 Javascript 时 运行ning,它从事件队列中拉出下一个事件并调用与该事件关联的 Javascript 回调并传递它是与事件关联的数据。这会触发最初传递给 fs.open() 的 Javascript 回调。

如果在上面的第二步中,线程池中没有可用的线程,则将任务添加到队列中,libuv 立即 returns 将控制权交还给 nodejs,这样它就可以 运行 其他 Javascript。稍后当池中的一个现有线程完成并完成将事件添加到事件队列的工作时,它将从线程池队列中拉出下一个项目,给它现在可用的线程并让它开始 运行 运行。

通过这种方式,所有文件操作从 Javascript 方面看来都是非阻塞和异步的。如果线程池中有可用线程,它们要么立即启动,要么在线程池队列中等待线程可用。该部分对事物的 Javascript 方面是不可见的。无论哪种方式,操作都会启动或排队并立即控制 returns 返回 nodejs 以继续 运行 其他 Javascript。而且,无论哪种方式,操作都会在稍后完成,并且通过 Javascript 事件队列调用与文件操作关联的 Javascript 回调。这提供了nodejs对所有文件使用的异步、非阻塞、事件驱动的机制I/O.