Node.js Event loop
node.js I/O事件循环是单线程还是多线程的?
如果我有几个I/O进程,那么node将它们放入一个外部事件循环中。它们是按顺序(最快的优先顺序)处理的,还是处理事件循环以同时处理它们(…以及哪些限制)?
事件循环
node.js事件循环在单个线程下运行,这意味着您编写的应用程序代码在单个线程上进行计算。nodejs本身通过libuv在下面使用了许多线程,但是在编写nodejs代码时,您永远不需要处理这些线程。
每次涉及I/O调用的调用都需要注册回调。此调用也会立即返回,这允许您并行执行多个IO操作,而不必在应用程序代码中使用线程。一旦I/O操作完成,它的回调将在事件循环上被推送。它将在执行之前在事件循环上推送的所有其他回调之后立即执行。
有几种方法可以对回调如何添加到事件循环中进行基本操作。通常你不需要这些,但偶尔它们会有用。
- 西米替米特
- 过程.nextick
在任何时候都不会有两个真正的并行执行路径,因此所有操作都是固有的线程安全的。通常会有几个由事件循环管理的异步并发执行路径。
阅读有关事件循环的更多信息
局限性
由于存在事件循环,节点不必为每个传入的TCP连接启动新线程。这允许节点同时服务成百上千个请求,只要您不计算每个请求的前1000个素数。
这也意味着不进行CPU密集型操作很重要,因为这些操作将在事件循环上保持锁,并阻止其他异步执行路径继续。同样重要的是不要使用所有I/O方法的
如果你想做CPU繁重的事情,你应该把它委托给一个不同的进程,这个进程可以更有效地执行CPU绑定的操作,或者你可以把它作为一个节点本机插件来写。
阅读有关用例的更多信息
控制流
为了管理编写许多回调,您可能需要使用控制流库。我相信这是目前最流行的基于回调的库:
- 网址:https://github.com/caolan/async
我使用过回电,它们让我疯狂,我有更好的使用承诺的经验,蓝鸟是一个非常流行和快速的承诺库:
- https://github.com/petkaantonov/bluebird
我发现这在节点社区中是一个非常敏感的话题(回调和承诺),所以无论如何,使用您认为对您个人最有用的东西。一个好的控制流库也应该为您提供异步堆栈跟踪,这对于调试非常重要。
当事件循环中的最后一个回调完成它的执行路径并且不注册任何其他回调时,node.js进程将完成。
这不是一个完整的解释,我建议您查看以下线程,它是最新的:
如何开始使用node.js
从威廉的回答来看:
The Node.js event loop runs under a single thread. Every I/O call requires you to register a callback. Every I/O call also returns immediately, this allows you to do multiple IO operations in parallel without using threads.
我想从上面的这句话开始解释,这是我在各处看到的节点JS框架的常见误解之一。
node.js不会仅用一个线程就神奇地处理所有这些异步调用,并且仍然保持该线程不被阻塞。它内部使用谷歌的V8引擎和一个名为LIBUV的库(用C++编写),使它能够将一些潜在的异步工作委托给其他工作线程(类似于等待从主节点线程委派任何工作的线程池)。然后,当这些线程完成它们的执行时,它们调用它们的回调,这就是事件循环如何意识到工作线程的执行已经完成的事实。
nodejs的要点和优点是,您永远不需要关心这些内部线程,它们将远离您的代码!.所有在多线程环境中正常发生的讨厌的同步工作都将由nodejs框架抽象出来,您可以在一个更为程序员友好的环境中(同时受益于多线程的所有性能增强)在单线程(主节点线程)上愉快地工作。
如果有人感兴趣,下面是一篇好文章:线程池何时使用?