有一种技术叫做分区
,你可以在NodeJs文档中了解它。但正如文档所述:
如果您需要执行更复杂的操作,则分区不是一个好选择。这是因为分区仅使用事件循环,而您几乎肯定无法从计算机上可用的多个核心中获得任何好处。
所以,您还可以使用另一种技术称为卸载,例如使用工作线程
或子进程
,但这也有一些缺点,例如必须对您希望在事件循环(当前线程)和工作线程或子进程之间共享的任何对象进行序列化和反序列化。
以下是我想出来的一个分区示例,它适用于express应用程序的上下文。
const express = require('express');
const crypto = require('crypto');
const randomstring = require('randomstring');
const app = express();
const port = 80;
app.get('/', async (req, res) => {
res.send('ok');
})
app.get('/block', async (req, res) => {
let result = [];
for (let i = 0; i < 10; ++i) {
result.push(await block());
}
res.send({result});
})
app.listen(port, () => {
console.log(`Listening on port ${port}`);
console.log(`http://localhost:${port}`);
})
const block = () => {
return new Promise((resolve, reject) => {
setImmediate(() => {
let hash = crypto.createHash("sha256");
const numberOfHasUpdates = 10e5;
for (let iter = 0; iter < numberOfHasUpdates; iter++) {
hash.update(randomstring.generate());
}
resolve(hash);
})
});
}
有两个端点
/
和
/block
,如果你访问了
/block
,然后再访问
/
端点,会发生这样一件事情,即
/
端点需要大约5秒钟才能返回响应(在“breathing space”期间(你称之为“break”))。
如果没有使用
setImmediate
,那么
/
端点将在for循环中调用
block
函数的次数乘以5后,约需等待
10 * 5
秒才能响应请求。
此外,你可以使用递归方法进行
分区,像这样:
function processItems(items, chunk) {
let i = 0;
const process = (done) => {
let currentChunk = chunk;
while (currentChunk > 0 && i < items?.length) {
--currentChunk;
syncBlock();
++i;
}
if (i < items?.length) {
setImmediate(process);
}
}
process();
}
如果您需要获取处理后的数据,可以像这样将其转换为promise:
function processItems(items, chunk) {
let i = 0;
let result = [];
const process = (done) => {
let currentChunk = chunk;
while (currentChunk > 0 && i < items?.length) {
--currentChunk;
const returnedValue = syncBlock();
result.push(returnedValue);
++i;
}
if (i < items?.length) {
setImmediate(() => process(done));
} else {
done && done(result);
}
}
const promisified = () => new Promise((resolve) => process(resolve));
return promisified();
}
你可以通过添加此路由处理程序来测试它,该处理程序与上面提供的其他处理程序一起使用:
app.get('/block2', async (req, res) => {
let result = [];
let arr = [];
for (let i = 0; i < 10; ++i) {
arr.push(i);
}
result = await processItems(arr, 1);
res.send({ result });
})
setTimeout
而不是一次性排队整个for loop
,那么每次它都会排队1000个中的一个,同时在它们之间允许其他请求进来。这样理解对吗? - Sihoon KimsetTimeout
是我需要的提示。但是,是的,需要用Promise来包装它。 - Sihoon Kim