节点JS处理器架构

时间:2019-02-08 07:10:19

标签: javascript node.js architecture

我试图获取有关节点js架构问题的解决方案。

我知道节点js是单线程的,并且可以用于事件循环和非阻塞机制。

但是我的问题是,其背后的处理器如何工作并在优先级基础上同步工作?或在一台核心计算机上同时处理多个请求。

试图通过创建两个API来验证这一点 在第一个API中,我创建了一个while循环 而在第二个API中,我创建了一个hello world的响应。

然后,我尝试同时击打API的第一个和第二个,但是第二个API等待第一个API结束,因此在这里,处理器直到第一个结束才使用第二个API。

所以我可以说节点js的处理器将以同步顺序工作,但不能并行运行吗?

所以所有请求都必须在队列中等待以前的请求才能完成?

2 个答案:

答案 0 :(得分:0)

在我看来,问题是,回答这个问题并不那么简单。

1)如果我们谈论的是ExpressJS,那么可以同步工作

2)但是,可以说我们谈论的是nodeJs的内置执行,例如http模块,它可以异步进行调用(但这取决于运行NodeJs的操作系统)。

NodeJ中的不同模块的行为从同步到异步都不同。 基于NodeJS V8的VUlibs实际上是基于C ++的库,其中大多数库都使用线程机制。就像加密模块可以在某种程度上异步运行执行。

答案 1 :(得分:0)

您的Javascript是单线程的-总是并且也不是抢先的。因此,一个事件发生了,一些Javascript开始响应该事件而运行,并且其他Javascript无法运行,直到该事件处理程序通过从调用该事件处理程序的回调返回而将控制权返回给解释器为止。

这时,另一个事件可以触发并运行另一个事件处理程序,并且在该事件处理程序返回系统之前,其他Javascript也无法运行。

这对于运行node.js的所有Javascript都是正确的。

嗯,但是您在node.js中所做的每一件事实际上都不是Javascript。假设您有两个简单的计时器:

console.log("A");
setTimeout(function() {
   console.log("B");
   fs.readFile("smallfile.txt", function(err, data) {
       console.log("C");
   });
   console.log("H");
}, 1000);

console.log("D");

setTimeout(function() {
   console.log("E");
   fs.readFile("bigfile.txt", function(err, data) {
       console.log("F");
   });
   console.log("I");
}, 1000);

console.log("G");

这将登录控制台

A
D
G
B
H
E
I
C
F

让我们讨论为什么会这样做。

A很明显,这是第一个语句。

然后,代码调用setTimeout(),这是非阻塞且异步的。因此,它所做的就是将计时器安排在将来的某个时间,然后立即返回。 setTimeout()回调函数无法为1000ms的调用准备就绪,因此现在不会被调用。

因此,在setTimeout()调用返回之后,我们执行console.log("D");

然后,它执行下一个setTimeout(),它再次只是将计时器安排为现在的1000ms,然后立即返回。

然后,它执行console.log("G");

这时,它将控制权返回给JS解释器,并且暂时无需执行任何其他操作。

然后,大约1000毫秒后,第一个setTimeout()计时器将计时器事件粘贴到事件队列中,并且由于JS解释器未运行任何其他Javascript,它将捕获该事件并运行与该事件关联的JS回调。立即记录console.log("B");

然后,它调用fs.readFile("smallfile.txt", ...)。这又是非阻塞且异步的,因此它所要做的就是告诉基础本机代码fs模块实现从该文件读取所有数据,然后立即返回。然后,它运行console.log("H");。至此,此事件处理程序已完成,并将控制权返回给解释器。

同时,第二个setTimeout()事件已经准备好,因此JS解释器从事件队列中提取该事件​​并调用与之关联的回调。

运行console.log("E");,然后调用fs.readFile(“ bigfile.txt”,...). This is again non-blocking and asynchronous so all it does is tell the underlying native code fs module implementation to go read all the data from this file and then returns immediately. It then runs console.log(“ I”);`。至此,此事件处理程序已完成,并将控制权返回给解释器。

一段时间后,fs.readFile("smallfile.txt", ...)完成并将事件插入事件队列。由于JS解释器无事可做,因此它将获取该事件并运行与之关联的回调,我们将看到console.log("C")的结果。然后完成,将控制权返回给解释器。

一段时间后,fs.readFile("bigfile.txt", ...)完成并将事件插入事件队列。由于JS解释器无事可做,因此它将获取该事件并运行与之关联的回调,我们将看到console.log("F")的结果。然后完成,将控制权返回给解释器。

至此,一切都完成了。

希望您能看到异步操作(以本机代码实现的操作如何与使用其他CPU内核的Javascript执行并行运行),以及如何通过将事件放在事件队列中与Javascript执行同步。当JS解释器运行完事件处理程序后,它可以在事件队列中查找要运行的下一个事件,或者,如果现在什么都没有,请进入睡眠状态,直到将下一个事件插入事件队列中。

因此,尽管本机代码实现可以与Javascript并行运行,但一次仅运行一个Javascript执行线程,而另一个线程则无法运行,直到前一个线程通过从任何内容返回来将控制权返回给解释器为止事件处理程序回调开始执行。

在事件循环内部,实际上有许多不同类型的队列用于不同类型的事件,并且它们相对于彼此具有不同的优先级,因此这比我之前描述的要复杂得多。这里的核心概念是一个事件驱动的系统,该系统一次运行仅与一个事件关联的Javascript(单线程),并且某些操作的本机代码实现可以与Javascript执行并行运行,并且与Javascript的单线程同步通过事件队列执行。