我知道Node.js使用单线程和事件循环来处理请求,每次只处理一个(这是非阻塞的)。但是,它是如何工作的,假设有10,000个并发请求。事件循环将处理所有的请求?那样不会太花时间吗?

我不明白(还)它怎么能比多线程web服务器快。我知道多线程web服务器在资源(内存,CPU)上更昂贵,但它不是更快吗?我可能错了;请解释这个单线程是如何在大量请求中更快的,以及它在处理大量请求(如10,000)时通常会做什么(在高层次上)。

还有,单线程能适应这么大的数量吗?请记住,我刚刚开始学习Node.js。


当前回答

多线程阻塞系统的阻塞部分使其效率较低。被阻塞的线程在等待响应期间不能用于其他任何事情。

而非阻塞单线程系统则充分利用了它的单线程系统。

见下图: 在这里,在厨房门口等待或在顾客挑选食物时等待,是“阻塞”了服务员的全部能力。在计算系统的意义上,它可以等待IO,或DB响应或任何阻塞整个线程的东西,即使线程在等待时能够进行其他工作。

让我们看看非阻塞是如何工作的:

在非阻塞系统中,服务员只接单和上菜,不在任何地方等待。他分享了他的手机号码,以便在他们完成订单后给他们回电话。同样地,他将自己的电话号码分享给厨房,以便在订单准备就绪时回复。

这就是Event循环在NodeJS中的工作方式,并且比阻塞多线程系统执行得更好。

其他回答

在slebetman的回答中补充: 当你说Node.JS可以处理10,000个并发请求时,它们本质上是非阻塞请求,即这些请求主要与数据库查询有关。

在内部,Node.JS的事件循环正在处理一个线程池,其中每个线程处理一个非阻塞请求,事件循环在将工作委派给线程池中的一个线程后继续侦听更多的请求。当其中一个线程完成工作时,它向事件循环发送一个信号,它已经完成,也就是回调。事件循环然后处理此回调并发回响应。

作为NodeJS的新手,请阅读更多关于nextTick的内容,以了解事件循环内部是如何工作的。 阅读http://javascriptissexy.com上的博客,当我开始使用JavaScript/NodeJS时,它们对我非常有帮助。

您可能认为大部分处理都是在节点事件循环中处理的。节点实际上将I/O工作分配给线程。I/O操作通常比CPU操作要长几个数量级,那么为什么CPU要等待呢?此外,操作系统已经可以很好地处理I/O任务。事实上,由于Node不等待,它实现了更高的CPU利用率。

通过类比的方式,可以将NodeJS想象成一个服务员,在I/O厨师在厨房里准备订单的同时接受客户的订单。其他系统有多名厨师,他们为顾客点单、准备饭菜、清理桌子,然后才为下一位顾客服务。

单线程事件循环模型处理步骤:

Clients Send request to Web Server. Node JS Web Server internally maintains a Limited Thread pool to provide services to the Client Requests. Node JS Web Server receives those requests and places them into a Queue. It is known as “Event Queue”. Node JS Web Server internally has a Component, known as “Event Loop”. Why it got this name is that it uses indefinite loop to receive requests and process them. Event Loop uses Single Thread only. It is main heart of Node JS Platform Processing Model. Event Loop checks any Client Request is placed in Event Queue. If not then wait for incoming requests for indefinitely. If yes, then pick up one Client Request from Event Queue Starts process that Client Request If that Client Request Does Not requires any Blocking IO Operations, then process everything, prepare response and send it back to client. If that Client Request requires some Blocking IO Operations like interacting with Database, File System, External Services then it will follow different approach Checks Threads availability from Internal Thread Pool Picks up one Thread and assign this Client Request to that thread. That Thread is responsible for taking that request, process it, perform Blocking IO operations, prepare response and send it back to the Event Loop very nicely explained by @Rambabu Posa for more explanation go throw this Link

添加slebetman的答案,以便更清楚地了解在执行代码时发生了什么。

The internal thread pool in nodeJs just has 4 threads by default. and its not like the whole request is attached to a new thread from the thread pool the whole execution of request happens just like any normal request (without any blocking task) , just that whenever a request has any long running or a heavy operation like db call ,a file operation or a http request the task is queued to the internal thread pool which is provided by libuv. And as nodeJs provides 4 threads in internal thread pool by default every 5th or next concurrent request waits until a thread is free and once these operations are over the callback is pushed to the callback queue. and is picked up by event loop and sends back the response.

现在这里有另一个信息,它不是单一的回调队列,有很多队列。

NextTick队列 微任务队列 定时器队列 IO回调队列(请求,文件操作,数据库操作) IO轮询队列 检查Phase queue或setimmediation 关闭处理程序队列

每当有请求时,代码就按照这个回调队列的顺序执行。

它不像当有一个阻塞请求时,它会附加到一个新线程。默认情况下只有4个线程。这是另一个排队过程。

在代码中,无论何时发生像文件读取这样的阻塞进程,然后调用一个从线程池中利用线程的函数,一旦操作完成,回调被传递到各自的队列,然后按顺序执行。

所有内容都基于回调的类型进行排队,并按照上面提到的顺序进行处理。

多线程阻塞系统的阻塞部分使其效率较低。被阻塞的线程在等待响应期间不能用于其他任何事情。

而非阻塞单线程系统则充分利用了它的单线程系统。

见下图: 在这里,在厨房门口等待或在顾客挑选食物时等待,是“阻塞”了服务员的全部能力。在计算系统的意义上,它可以等待IO,或DB响应或任何阻塞整个线程的东西,即使线程在等待时能够进行其他工作。

让我们看看非阻塞是如何工作的:

在非阻塞系统中,服务员只接单和上菜,不在任何地方等待。他分享了他的手机号码,以便在他们完成订单后给他们回电话。同样地,他将自己的电话号码分享给厨房,以便在订单准备就绪时回复。

这就是Event循环在NodeJS中的工作方式,并且比阻塞多线程系统执行得更好。