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

时间:2014-01-31 17:08:05

标签: javascript node.js nonblocking

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

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

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

由于 基督教

3 个答案:

答案 0 :(得分:33)

You need to read about libuv,节点的非阻塞I / O背后的“魔力”。

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

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

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

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

答案 1 :(得分:5)

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

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

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

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


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

答案 2 :(得分:1)

Node.js不需要旋转新线程来处理每个Web请求这一事实在您拥有大量并发连接的环境中成为一个优势(如数千或数万个并发连接)。下面你可能不会看到像Java / Apache或C#/ IIS这样的线程环境有任何显着差异,因为这些平台现在已经得到了很好的优化。

优点是,即使Node.js要为I / O操作(在某些情况下可能在某些情况下而不是在其他情况下)旋转新线程,您仍然可以减少处理Web请求所需的线程数量每次请求1次1.再次,如果您正在处理数以千计的并发连接,这将获得巨大收益。