[在节点中使用Express制作REST服务时,如何防止阻止任务阻止整个rest服务?以以下特快专递服务为例:
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello, World'));
const blockService = async function () {
return new Promise((resolve, reject) => {
const end = Date.now() + 20000;
while (Date.now() < end) {
const doSomethingHeavyInJavaScript = 1 + 2 + 3;
}
resolve('I am done');
});
}
const blockController = function (req, res) {
blockService().then((val) => {
res.send(val);
});
};
app.get('/block', blockController);
app.listen(3000, () => console.log('app listening on port 3000'));
在这种情况下,对/ block的调用将使整个服务在20秒钟内无法访问。如果有许多客户端在使用该服务,这将是一个大问题,因为在此期间,其他客户端将无法访问该服务。这显然是while循环阻塞代码并因此挂起主线程的问题。该代码可能令人困惑,因为尽管在blockService中使用了promise,主线程仍然挂起。如何确保blockService将运行工作线程而不是事件循环?
默认情况下,node.js在单个线程中运行Javascript代码。因此,如果您在请求处理程序中确实有CPU密集型代码(如上所示),那确实是一个问题。您的选择如下:
启动工作线程并在工作线程中运行CPU密集型代码。从版本10开始,node.js为此已具有辅助线程。然后,您可以通过消息传递将结果传回主线程。
启动运行node.js代码或任何类型代码的任何其他进程,并在该其他进程中计算结果。然后,您可以通过消息传递将结果传回主线程。
使用节点集群来启动N个进程,以便一旦某个进程因CPU密集型操作而停滞,希望其他进程中的至少一个可以自由运行其他请求。
[请注意,服务器所做的许多事情,例如读取文件,进行网络连接,向数据库发出请求都是异步且无阻塞的,因此实际上拥有大量CPU密集型代码并不罕见。因此,如果这只是您自己的一个好奇的例子,那么在设计线程或集群之前,应确保服务器中确实存在CPU密集型问题。
Node.js是使用单个运行时线程的基于事件的模型。由于您发现的原因,Node.js并不是CPU绑定任务(或同步阻止任务)的理想选择。 Node.js最适合异步协调I / O。
worker-threads在Node.js v12中发布。这使您可以使用另一个线程来阻止任务。它们相对简单易用,如果您绝对需要卸载阻止任务,则可以使用。