我想了解node.js的内部工作原理,我有意包括计算任务(循环)。但是我发现它还是阻塞了主线程。
这是我的脚本
console.log("start");
for (let i = 0; i < 10; i++) {
console.log(i)
}
console.log("end")
o/p是: start
1
2
3.
……
10
结束
但是,根据node.js架构,高计算任务不应该由从线程池和事件循环中挑选的不同线程执行,继续执行非阻塞任务吗?
我使用此链接enter link description here引用node.js内部架构
有人能解释一下脚本的架构和行为吗?
发布于 2021-10-13 16:23:53
默认情况下,nodejs只使用一个线程来运行Javascript。这意味着(除非你使用WorkerThreads,它本质上是一个完全独立的虚拟机),一次只有一段Javascript在运行。Nodejs不会“检测”某个长时间运行的Javascript片段,并将其移动到另一个线程。它根本没有这样的功能。如果你有一些长时间运行的同步Javascript片段,它将阻塞事件循环,并阻塞所有其他Javascript和所有其他事件处理。
在其实现的内部,nodejs有一个线程池,用于某些类型的本机代码(文件I/O和加密操作的内部实现)。这只支持文件I/O和加密操作的异步实现-它不能并行运行Javascript。
因此,您显示的脚本如下:
console.log("start");
for (let i = 0; i < 10; i++) {
console.log(i)
}
console.log("end")
是完全同步的,并按顺序运行,并在运行时阻止所有其他Javascript运行,因为它在运行时使用一个线程来运行Javascript。
Nodejs的出色可伸缩性来自其异步I/O模型,该模型无需使用单独的线程即可同时执行大量异步操作。但是,请记住,这些异步I/O操作背后都有本机代码(其中一些可能在其本机代码实现中使用线程)。
但是,如果您有长期运行的同步Javascript操作(比如使用Javascript编写的图像分析),则通常需要将这些操作移出主事件循环线程,方法是将它们分流到WorkerThreads或其他进程,或者分流到可能使用OS线程的本机代码实现。
,但是根据node.js架构,高计算任务不应该由从线程池和事件循环中挑选的不同线程执行,继续执行非阻塞任务吗?
不,这不是nodejs的工作方式,也不是对您显示的图表的正确解释。线程池不用于运行Javascript。用于一些API的内部实现,例如文件I/O和一些加密操作。它不用于运行您的Javascript。只有一个主线程用于运行您的Javascript (除非您专门在WorkerThread中运行代码)。
我想了解node.js的内部工作原理,我有意包含计算任务(
循环)。但是我发现它还是阻塞了主线程。
是的,for
循环(不包含等待promise的await
语句)将完全占用单个Javascript线程,并在for
循环运行时阻止事件循环处理其他事件。
发布于 2021-10-13 16:09:45
JS中绝对没有线程(除非您显式地使用工作线程)。Javascript使用cooperative multi-tasking,这意味着一个函数总是在下一个函数开始之前完成。将控制权交还给调度器的唯一另一种方法是将任务分离到另一个异步调用的函数中。所以在你的例子中,例如,你可以这样做:
console.log("start");
setTimeout(() => {
for (let i = 0; i < 10; i++) {
console.log(i)
}}, 0);
console.log("end")
你会得到:
start
end
1
2
..
9
这也回答了您关于繁重计算的问题:除非您使用相对较新的worker threads,否则您不能在不使用本机代码的情况下在node.js中“在后台”运行繁重的计算。
因此,如果你真的有很重的负载,你有三个选择:
发布于 2021-10-13 16:19:14
JS执行它的代码同步。很少有像setInterval
或setTimout
这样的东西会被称为“异步鼠标”。但这实际上并不完全正确。异步意味着事情是并行完成的,但事实并非如此。看看setTimeout
吧。通过执行它,您可以将函数添加到任务que中,稍后事件循环从que中获取它,并将其放入堆栈并执行它,即syncrhonouse。如果您想真正并行地执行一些事情,那么您应该考虑使用工作线程
https://stackoverflow.com/questions/69558694
复制相似问题