js中的单线程和事件循环

时间:2021-07-17 23:57:43

First of all, I am starter trying to understand what is Node.Js. I have two questions.

首先,我开始尝试理解Node.Js是什么。我有两个问题。

First Question
From the article of Felix, it said "there can only be one callback firing at the same time. Until that callback has finished executing, all other callbacks have to wait in line".

第一个问题来自Felix的文章,它说“同一时间只能有一个回调。”在回调完成执行之前,所有其他回调都必须排队等候。

Then, consider about the following code (copied from nodejs official website)

然后,考虑以下代码(从nodejs官方网站复制)

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8124, "127.0.0.1");

If two client requests are received simultaneously, it means the following workflow:

如果同时接收两个客户端请求,则意味着以下工作流程:

  1. First http request event received, Second request event received.
  2. 收到第一个http请求事件,收到第二个请求事件。
  3. As soon as first event received, callback function for first event is executing.
  4. 一旦收到第一个事件,就执行第一个事件的回调函数。
  5. At while, callback function for second event has to be waiting.
  6. 此时,第二个事件的回调函数必须等待。

Am I right? If I am right, how Node.js control if there are thousands of client request within very short-time duration.

我说的对吗?如果我是对的,如何节点。如果在很短的时间内有数千个客户端请求,则使用js控制。

Second Question
The term "Event Loop" is mostly used in Node.js topic. I have understood "Event Loop" as the following from http://www.wisegeek.com/what-is-an-event-loop.htm;

第二个问题,“事件循环”一词在Node中最常用。js的话题。我从http://www.wisegeek.com/what-is-an-event-loop.htm理解“事件循环”如下;

An event loop - or main loop, is a construct within programs that controls and dispatches events following an initial event.

事件循环或主循环是程序中的一个结构,它控制并在初始事件之后分派事件。

The initial event can be anything, including pushing a button on a keyboard or clicking a button on a program (in Node.js, I think the initial events will be http request, db queries or I/O file access).

初始事件可以是任何东西,包括按键盘上的按钮或单击程序上的按钮(在节点中)。我认为最初的事件将是http请求、db查询或I/O文件访问)。

This is called a loop, not because the event circles and happens continuously, but because the loop prepares for an event, checks the event, dispatches an event and repeats the process all over again.

这被称为循环,不是因为事件循环并连续发生,而是因为循环为事件做了准备,检查事件,分派事件并重复整个过程。

I have a conflict about second paragraph especially the phrase"repeats the process all over again". I accepted that the above http.createServer code from above question is absolutely "event loop" because it repeatedly listens the http request events.

我对第二段有异议,尤其是“从头再来一遍”这句话。我接受上面的http。上面问题中的createServer代码绝对是“事件循环”,因为它反复监听http请求事件。

But I don't know how to identify the following code as whether event-driven or event loop. It does not repeat anything except the callback function fired after db query is finished.

但我不知道如何识别以下代码:事件驱动或事件循环。除了在db查询完成后触发的回调函数外,它不重复任何操作。

database.query("SELECT * FROM table", function(rows) {
  var result = rows;
});

Please, let me hear your opinions and answers.

请让我听听你的意见和答案。

2 个解决方案

#1


8  

Answer one, your logic is correct: second event will wait. And will execute as far as its queued callbacks time comes.

回答一,你的逻辑是正确的:第二个事件将等待。并将执行到其队列回调时间。

As well, remember that there is no such thing as "simultaneously" in technical world. Everything have very specific place and time.

同样,记住在技术世界里没有“同时”这样的事情。每件事都有特定的地点和时间。

The way node.js manages thousands of connections is that there is no need to hold thread idling while there is some database call blocking the logic, or another IO operation is processing (like streams for example). It can "serve" first request, maybe creating more callbacks, and proceed to others.
Because there is no way to block the execution (except nonsense while(true) and similar), it becomes extremely efficient in spreading actual resources all over application logic.

节点的方式。js管理数千个连接,当有一些数据库调用阻塞逻辑时,不需要保持线程空闲,或者另一个IO操作正在处理(例如流)。它可以“服务”第一个请求,可能创建更多回调,然后继续到其他请求。因为没有方法阻止执行(除了无意义的(正确的)和类似的),所以它在将实际资源分散到应用程序逻辑上变得非常高效。

Threads - are expensive, and server capacity of threads is directly related to available Memory. So most of classic web applications would suffer just because RAM is used on threads that are simply idling while there is database query block going on or similar. In node that's not a case.

线程——是昂贵的,并且线程的服务器容量直接与可用内存相关。因此,大多数经典的web应用程序都会受到影响,因为RAM仅用于在数据库查询块正在运行或类似情况下空闲的线程。在node,情况并非如此。

Still, it allows to create multiple threads (as child_process) through cluster, that expands even more possibilities.

不过,它允许通过集群创建多个线程(作为child_process),这将扩展更多的可能性。

Answer Two. There is no such thing as "loop" that you might thinking about. There will be no loop behind the scenes that does checks if there is connections or any data received and so on. It is nowadays handled by Async methods as well.

两个回答。没有你可能会想到的“循环”这种东西。在后台没有循环来检查是否有连接或接收到任何数据等等。现在它也被异步方法处理了。

So from application point of view, there is no 'main loop', and everything from developer point of view is event-driven (not event-loop).

因此,从应用程序的角度来看,没有“主循环”,从开发人员的角度来看,一切都是事件驱动的(不是事件循环)。

In case with http.createServer, you bind callback as response to requests. All socket operations and IO stuff will happen behind the scenes, as well as HTTP handshaking, parsing headers, queries, parameters, and so on. Once it happens behind the scenes and job is done, it will keep data and will push callback to event loop with some data. Once event loop ill be free and will come time it will execute in node.js application context your callback with data from behind the scenes.

与http。createServer,您将回调绑定为对请求的响应。所有套接字操作和IO内容都将在幕后发生,以及HTTP握手、解析头、查询、参数等等。一旦它在幕后发生并完成任务,它将保存数据,并使用一些数据将回调推到事件循环。一旦事件循环不存在,它将在节点中执行。js应用程序上下文您的回调与后台的数据。

With database request - same story. It ill prepare and ask stuff (might do it even async again), and then will callback once database responds and data will be prepared for application context.

与数据库请求-同样的故事。它会准备并询问一些东西(甚至可能再次异步执行),然后在数据库响应并为应用程序上下文准备数据时将回调。

To be honest, all you need with node.js is to understand the concept, but not implementation of events. And the best way to do it - experiment.

老实说,您需要的是node。js的目的是理解事件的概念,而不是实现事件。最好的方法是做实验。

#2


1  

1) Yes, you are right.

是的,你说得对。

It works because everything you do with node is primarily I/O bound.

它之所以有效,是因为您对node所做的一切基本上都是受I/O限制的。

When a new request (event) comes in, it's put into a queue. At initialization time, Node allocates a ThreadPool which is responsible to spawn threads for I/O bound processing, like network/socket calls, database, etc. (this is non-blocking).

当一个新的请求(事件)传入时,它将被放入队列中。在初始化时,节点分配一个线程池,该线程池负责为I/O绑定的处理生成线程,如网络/套接字调用、数据库等(这是非阻塞的)。

Now, your "callbacks" (or event handlers) are extremely fast because most of what you are doing is most likely CRUD and I/O operations, not CPU intensive.

现在,您的“回调”(或事件处理程序)非常快,因为您正在做的大多数操作很可能是CRUD和I/O操作,而不是CPU密集型操作。

Therefore, these callbacks give the feeling that they are being processed in parallel, but they are actually not, because the actual parallel work is being done via the ThreadPool (with multi-threading), while the callbacks per-se are just receiving the result from these threads so that processing can continue and send a response back to the client.

因此,这些回调给他们被并行处理的感觉,但实际上不是这样,因为实际的并行工作正在通过ThreadPool(多线程),当回调本身只是接收结果从这些线程,以便能继续处理并将响应发送回客户端。

You can easily verify this: if your callbacks are heavy CPU tasks, you can be sure that you will not be able to process thousands of requests per second and it scales down really bad, comparing to a multi-threaded system.

您可以很容易地验证这一点:如果回调是繁重的CPU任务,那么您可以确保您不能每秒处理数千个请求,并且与多线程系统相比,它的规模非常小。

2) You are right, again.

你又说对了。

Unfortunately, due to all these abstractions, you have to dive in order to understand what's going on in background. However, yes, there is a loop.

不幸的是,由于所有这些抽象,你必须潜水才能了解背景中发生了什么。但是,有一个循环。

In particular, Nodejs is implemented with libuv.

特别是Nodejs是用libuv实现的。

Interesting to read.

有趣的阅读。

But I don't know how to identify the following code as whether event-driven or event loop. It does not repeat anything except the callback function fired after db query is finished.

但我不知道如何识别以下代码:事件驱动或事件循环。除了在db查询完成后触发的回调函数外,它不重复任何操作。

Event-driven is a term you normally use when there is an event-loop, and it means an app that is driven by events such as click-on-button, data-arrived, etc. Normally you associate a callback to such events.

事件驱动是当有事件循环时通常使用的术语,它指的是由事件驱动的应用程序,如单击按钮、数据到达等。

#1


8  

Answer one, your logic is correct: second event will wait. And will execute as far as its queued callbacks time comes.

回答一,你的逻辑是正确的:第二个事件将等待。并将执行到其队列回调时间。

As well, remember that there is no such thing as "simultaneously" in technical world. Everything have very specific place and time.

同样,记住在技术世界里没有“同时”这样的事情。每件事都有特定的地点和时间。

The way node.js manages thousands of connections is that there is no need to hold thread idling while there is some database call blocking the logic, or another IO operation is processing (like streams for example). It can "serve" first request, maybe creating more callbacks, and proceed to others.
Because there is no way to block the execution (except nonsense while(true) and similar), it becomes extremely efficient in spreading actual resources all over application logic.

节点的方式。js管理数千个连接,当有一些数据库调用阻塞逻辑时,不需要保持线程空闲,或者另一个IO操作正在处理(例如流)。它可以“服务”第一个请求,可能创建更多回调,然后继续到其他请求。因为没有方法阻止执行(除了无意义的(正确的)和类似的),所以它在将实际资源分散到应用程序逻辑上变得非常高效。

Threads - are expensive, and server capacity of threads is directly related to available Memory. So most of classic web applications would suffer just because RAM is used on threads that are simply idling while there is database query block going on or similar. In node that's not a case.

线程——是昂贵的,并且线程的服务器容量直接与可用内存相关。因此,大多数经典的web应用程序都会受到影响,因为RAM仅用于在数据库查询块正在运行或类似情况下空闲的线程。在node,情况并非如此。

Still, it allows to create multiple threads (as child_process) through cluster, that expands even more possibilities.

不过,它允许通过集群创建多个线程(作为child_process),这将扩展更多的可能性。

Answer Two. There is no such thing as "loop" that you might thinking about. There will be no loop behind the scenes that does checks if there is connections or any data received and so on. It is nowadays handled by Async methods as well.

两个回答。没有你可能会想到的“循环”这种东西。在后台没有循环来检查是否有连接或接收到任何数据等等。现在它也被异步方法处理了。

So from application point of view, there is no 'main loop', and everything from developer point of view is event-driven (not event-loop).

因此,从应用程序的角度来看,没有“主循环”,从开发人员的角度来看,一切都是事件驱动的(不是事件循环)。

In case with http.createServer, you bind callback as response to requests. All socket operations and IO stuff will happen behind the scenes, as well as HTTP handshaking, parsing headers, queries, parameters, and so on. Once it happens behind the scenes and job is done, it will keep data and will push callback to event loop with some data. Once event loop ill be free and will come time it will execute in node.js application context your callback with data from behind the scenes.

与http。createServer,您将回调绑定为对请求的响应。所有套接字操作和IO内容都将在幕后发生,以及HTTP握手、解析头、查询、参数等等。一旦它在幕后发生并完成任务,它将保存数据,并使用一些数据将回调推到事件循环。一旦事件循环不存在,它将在节点中执行。js应用程序上下文您的回调与后台的数据。

With database request - same story. It ill prepare and ask stuff (might do it even async again), and then will callback once database responds and data will be prepared for application context.

与数据库请求-同样的故事。它会准备并询问一些东西(甚至可能再次异步执行),然后在数据库响应并为应用程序上下文准备数据时将回调。

To be honest, all you need with node.js is to understand the concept, but not implementation of events. And the best way to do it - experiment.

老实说,您需要的是node。js的目的是理解事件的概念,而不是实现事件。最好的方法是做实验。

#2


1  

1) Yes, you are right.

是的,你说得对。

It works because everything you do with node is primarily I/O bound.

它之所以有效,是因为您对node所做的一切基本上都是受I/O限制的。

When a new request (event) comes in, it's put into a queue. At initialization time, Node allocates a ThreadPool which is responsible to spawn threads for I/O bound processing, like network/socket calls, database, etc. (this is non-blocking).

当一个新的请求(事件)传入时,它将被放入队列中。在初始化时,节点分配一个线程池,该线程池负责为I/O绑定的处理生成线程,如网络/套接字调用、数据库等(这是非阻塞的)。

Now, your "callbacks" (or event handlers) are extremely fast because most of what you are doing is most likely CRUD and I/O operations, not CPU intensive.

现在,您的“回调”(或事件处理程序)非常快,因为您正在做的大多数操作很可能是CRUD和I/O操作,而不是CPU密集型操作。

Therefore, these callbacks give the feeling that they are being processed in parallel, but they are actually not, because the actual parallel work is being done via the ThreadPool (with multi-threading), while the callbacks per-se are just receiving the result from these threads so that processing can continue and send a response back to the client.

因此,这些回调给他们被并行处理的感觉,但实际上不是这样,因为实际的并行工作正在通过ThreadPool(多线程),当回调本身只是接收结果从这些线程,以便能继续处理并将响应发送回客户端。

You can easily verify this: if your callbacks are heavy CPU tasks, you can be sure that you will not be able to process thousands of requests per second and it scales down really bad, comparing to a multi-threaded system.

您可以很容易地验证这一点:如果回调是繁重的CPU任务,那么您可以确保您不能每秒处理数千个请求,并且与多线程系统相比,它的规模非常小。

2) You are right, again.

你又说对了。

Unfortunately, due to all these abstractions, you have to dive in order to understand what's going on in background. However, yes, there is a loop.

不幸的是,由于所有这些抽象,你必须潜水才能了解背景中发生了什么。但是,有一个循环。

In particular, Nodejs is implemented with libuv.

特别是Nodejs是用libuv实现的。

Interesting to read.

有趣的阅读。

But I don't know how to identify the following code as whether event-driven or event loop. It does not repeat anything except the callback function fired after db query is finished.

但我不知道如何识别以下代码:事件驱动或事件循环。除了在db查询完成后触发的回调函数外,它不重复任何操作。

Event-driven is a term you normally use when there is an event-loop, and it means an app that is driven by events such as click-on-button, data-arrived, etc. Normally you associate a callback to such events.

事件驱动是当有事件循环时通常使用的术语,它指的是由事件驱动的应用程序,如单击按钮、数据到达等。