单线程事件循环与Node.JS中的多线程非阻塞工作器

Chr*_*ian 11 javascript nonblocking node.js

Node.JS最大的优点是它具有非阻塞性.它是单线程的,因此不需要为每个新的传入连接生成一个新线程.

在事件循环(实际上是单线程)后面,有一个"非阻塞工作者".这个东西不再是单线程了,所以(据我所知)它可以为每个任务生成一个新线程.

也许我误解了一些东西,但究竟哪里有优势.如果要处理的任务很多,那么非阻塞工作会不会变成阻塞工作者?

谢谢Christian

jos*_*736 37

您需要了解libuv,它是节点的非阻塞I/O背后的"神奇".

从libuv书中拿走的重要一点是libuv使用主机操作系统的异步 I/O 工具 ; 它不是简单地为每个连接创建一个新线程.

libuv告诉操作系统,它想知道在特定套接字上发生的任何更改(连接状态,接收的数据等).然后由OS来处理管理连接.操作系统本身可以创建一个或多个线程来实现这一点,但这不是我们关注的问题.(它肯定不会为每个连接创建一个线程.)

对于其他类型的操作,例如对C库的调用可能计算成本很高(即加密),libuv提供了一个线程池,可以在其上运行这些操作.由于它是一个线程池,因此您不必担心线程计数在没有绑定的情况下增长.当池完全忙碌时,操作会排队.

所以是的,JavaScript运行在一个线程上.是的,node(通过libuv)在后台产生许多线程来完成工作,因此它不需要阻止JavaScript线程.但是,线程计数始终受到控制,并且I/O通常甚至不会获得自己的节点分配线程,因为这是由OS处理的.


Hal*_*yon 5

好吧,让我们稍微打破一下.单线程应用程序具有以下优点:您永远不会遇到死锁或竞争条件.这些问题源于多线程系统中的同时内存访问.如果两个线程访问同一条信息,可能会发生奇怪的事情.

那么为什么JavaScript有工人呢?如果你需要做一些繁重的处理,你将阻止事件循环,你可以尝试通过生成计时器事件来分散工作负载,但这很乏味.Worker允许您在一个条件下生成一个线程:没有共享内存访问.这解决了单线程环境中繁重处理的问题,同时避免了多线程环境(死锁,竞争条件)的陷阱.

正如@dandavis所说,如果你有一个多核CPU(现在每个人都这么做),可以将Worker线程卸载到其他核心.

你必须要明白,虽然JavaScript是单线程的,但它周围的环境仍然是非常多线程的.在Node.JS中读取文件是非阻塞的,但可能有一个线程在操作系统中支持它.


作为一个小的附录我会说Node.JS的最大优点是它允许你在服务器上编写JavaScript,这允许你在客户端和服务器之间共享代码.事实上它是非阻塞的很好但是线程已经解决了这个问题.非阻塞IO源于单线程.拥有阻塞IO的单个线程非常不方便.