如何在node.js中进行大量处理操作

8

我有一个需要同时处理10-12个请求的大量数据处理操作。我了解到,为了实现更高水平的并发性,Node.js是一个不错的平台,它通过非阻塞事件循环来实现。

我知道,如果要查询数据库等操作,可以将事件分离到单独的进程(例如 mongodmysqld),然后使用回调函数处理该进程的结果,这个方法也很好理解。

但是,如果我想在回调函数中执行繁重的计算任务,那么它会阻塞其他请求,直到该回调函数中的代码全部执行完毕。例如,我想处理一张高分辨率的图像,而我的代码是JavaScript本身编写的(没有单独的进程来处理图像)。

我认为实现的方式是:

get_image_from_db(image_id, callback(imageBitMap) {
    heavy_operation(imageBitMap); // Can take 5 seconds.
});

那个 heavy_operation 会导致节点在那 5 秒内无法接收任何请求吗?或者我想错了做这样的任务的方式。请指导,我是JS新手。

更新

或者可以这样,我可以处理部分图片并使事件循环返回以处理其他回调,并返回处理该部分图片(类似于优先处理事件)。

3个回答

5
是的,它会阻塞它,因为回调函数是在主循环中执行的。只有异步调用的函数才不会阻塞循环。我理解的是,如果你想让图像处理异步执行,你需要使用单独的进程来处理它。
请注意,您可以编写自己的异步进程来处理它。首先,您可以阅读如何为Node.js编写异步函数的答案。
更新: 如何在Node.js中创建非阻塞异步函数? 也值得一读。实际上,这个问题被引用在我链接的另一个问题中,但为了简单起见,我想在这里包含它。

但是,如果我为这个繁重的操作有单独的进程,并且有15个请求到达。那么是否会创建15个进程。那将是非常昂贵的。我不能在node中创建线程吗。顺便说一句,感谢您的答案。一旦我澄清了我的疑惑,我会接受它 :) - Sushant Gupta
2
是的,它将创建15个进程,并且据我所知,您无法在Node中创建线程。它只有一个线程,即主事件循环。另一个选择是编写一个单独的Node工作器应用程序,通过消息队列(RabbitMQ或其他)传递任务进行图像处理。然而,这只会同步处理图像(一次处理一个)。如果您想要同时处理它们,您必须创建单独的进程。 - Nick Mitchinson
我现在明白了。感谢你的帮助和时间,伙计。 - Sushant Gupta

4
当回调函数执行大量计算时,事件循环将被阻塞直到计算完成。这意味着回调函数将会阻塞事件循环5秒钟。 我的解决方案 可以使用生成器函数将控制权交还给事件循环。我将使用一个运行3秒钟的while循环作为长时间运行的回调函数。 没有生成器函数
let start = Date.now();

setInterval(() => console.log('resumed'), 500);
function loop() {
    while ((Date.now() - start) < 3000) { //while the difference between Date.now() and start is less than 3 seconds
        console.log('blocked')
    }
}

loop();

输出结果将是:
// blocked
// blocked
//
//  ... would not return to the event loop while the loop is running
//
// blocked
//...when the loop is over then the setInterval kicks in
// resumed
// resumed

使用生成器函数

let gen;
let start = Date.now();

setInterval(() => console.log('resumed'), 500);

function *loop() {
    while ((Date.now() - start) < 3000) { //while the difference between Date.now() and start is less than 3 seconds
        console.log(yield output())
    }
}

function output() {
    setTimeout(() => gen.next('blocked'), 500)
}

gen = loop();
gen.next();

输出如下:
// resumed
// blocked
//...returns control back to the event loop while though the loop is still running
// resumed
// blocked
//...end of the loop
// resumed
// resumed
// resumed

使用JavaScript生成器可以帮助运行重型计算函数,这些函数在计算时会将控制权“yield”回事件循环。如需了解更多关于事件循环的知识,请访问https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/function*
更多内容请参考:https://davidwalsh.name/es6-generators

4

很遗憾,我还没有足够的声望来评论Nick的回答,但是您是否看过Node的集群API?它目前仍处于实验阶段,但它可以允许您产生多个线程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接