是什么导致node.js处理删除多线程状态的阻塞状态?

时间:2019-02-01 23:18:38

标签: javascript node.js multithreading parallel-processing fork

我正在尝试制造一个“多线程”快速服务器,该服务器将生成一个将执行任务的进程。

这背后的整个想法,将是我的重构密集的高单线程应用程序的Node.js,这样我就可以产生更多的过程,因此在同一时间运行单独的密集型任务。

// Primary app (master).
// File called: app.js
const express = require('express');
const { fork } = require('child_process');
const app = express();

var counter = 0;
app.post('/intensiveTask', async (req, res) => {
    try {
        const forked = fork('./child.js');
        console.log(`forked child: ${++counter}`)
        forked.send(counter);
        forked.on('message', (m) => {
              console.log('from child: ' + m);
              res.sendStatus(200);
              forked.kill();
        });
     } catch (err) {
        console.log(err.stack)
        res.json({ error: err.message || err.toString() });
     }
});

try {
    app.listen(8080);
} catch (err) {
    console.error(`Failed to start the server due to the following error: ${err}`);
}


// Process app (child).
// File called: child.js

process.on('message', (m) => {
    console.log('inside child: ' + m);

    var time = Math.floor(Math.random() * Math.floor(5000));
    console.log(`about to wait ${time} for process ${m}`);

    setTimeout(() => {
        process.send(`finish... ${m}`);
    }, time);

});

我遇到的主要问题与使用JMeter的这些结果有关: 对于50个线程,我大约有16s。 对于100个线程,我大约需要32秒。 问题是它们都同时到达。我希望很快会收到第一个请求,而最终不会同时全部发出。 所以我想知道造成这种阻塞状态的原因是什么...

In the begining block: 
...
forked child: 176
forked child: 177
forked child: 178
forked child: 179
...
In the midddle block:
...
about to wait 735 for process 159
about to wait 4475 for process 133
about to wait 518 for process 131
inside childe: 125
about to wait 3909 for process 100
...
At the end, a block of finishing state :
...
from child: finish... 84
from child: finish... 81
from child: finish... 83
from child: finish... 88
...

1 个答案:

答案 0 :(得分:1)

如果您启动100个进程并要求它们全部执行相同数量的CPU密集型工作,则您的操作系统将尝试尽可能平均地在这100个进程之间共享CPU。这将导致大约相同的时间所有100只处理到结束。

此外,启动整个正在执行CPU密集型工作的工作进程比在CPU中拥有内核要高得多,因为这会给OS带来持续不断的时间开销,因此整个系统启动效率更高。它们之间的切片,从总吞吐量减损。

如果,您想要的是首先到达的第一个任务(明显在后面的任务之前),最后一个要最后完成的任务,那么架构所需的就是工作队列。

您可以创建与核心一样多的工作进程,并为传入的工作创建队列。当传入请求到达时,您会看到是否有空闲工作人员。如果有,则将工作交给免费工人。如果没有空闲工作者,则请求进入FIFO队列。当工人完成的一个,你再抓住从队列中最早的项目,并通过该请求不仅仅是完成了工人。这种体系结构将使第一个请求尽快完成,并让后面的请求等待。它也可以扩展到更大的负载,因为很明显,如果您为每个新请求创建一个新进程,很快就会有如此多的进程,以至于您已经消耗了服务器上的大量资源(尤其是内存),并且所有进程都在竞争彼此。

对于你的另一个选择是使用在node.js中的聚类模块这将为系统中的每个CPU内核创建一个进程,并将自动将传入请求传递给这些进程之一,包括传递实际的传入HTTP连接,以便工作人员甚至可以为您发送响应。

我没有特别的建议,但是已经为node.js编写了作业队列模块,因此您也可以使用其中一个而不是自己编写。