在节点中使用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将运行工作线程而不是事件循环?
启动工作线程并在工作线程中运行CPU密集型代码。从版本10开始,node.js就有了用于此目的的工作线程。然后通过消息传递将结果反馈给主线程。
启动任何其他运行node.js代码或任何类型代码的进程,并在其他进程中计算结果。然后通过消息传递将结果反馈给主线程。
使用节点集群来启动N个进程,这样,一旦进程陷入CPU密集型操作,至少有一个进程可以自由运行其他请求。
请注意,服务器所做的很多事情,如读取文件、建立网络、向数据库发出请求,都是异步和非阻塞的,因此实际上有大量CPU密集型代码并不常见。因此,如果这只是一个为你自己的好奇心而编造的例子,那么在设计线程或集群之前,你应该确保你的服务器中确实存在CPU密集型问题。
Node.js是一个基于事件的模型,使用单个运行时线程。由于您已经发现的原因,Node.js不是CPU绑定任务(或同步阻塞任务(的好选择。Node.js最适合异步协调I/O。工作线程在Node.js v12中发布。这允许您使用另一个线程来阻止任务。它们使用起来相对简单,如果你绝对需要卸载阻塞任务,它们也可以工作。