节点版本: v10.13.0
我正在尝试对涉及大量CPU计算的NodeJS请求并发进行非常简单的测试。我知道NodeJS并不是处理CPU绑定进程的最佳工具,并且不应系统地生成子进程,但是此代码是为了测试子进程的工作原理。这也是使用NestJS以TypeScript编写的。
src / app.controller.ts
import { Get, Param, Controller } from '@nestjs/common';
import fork = require('child_process');
@Controller()
export class AppController {
@Get()
async root(): Promise<string> {
let promise = new Promise<string>(
(resolve, reject) => {
// spawn new child process
const process = fork.fork('./src/cpu-intensive.ts');
process.on('message', (message) => {
// when process finished, resolve
resolve( message.result);
});
process.send({});
}
);
return await promise;
}
}
src / cpu-tensive.ts
process.on('message', async (message) => {
// simulates a 10s-long process
let now = new Date().getTime();
let waittime = 10000; // 10 seconds
while (new Date().getTime() < now + waittime) { /* do nothing */ };
// send response to master process
process.send({ result: 'Process ended' });
});
如此长的流程(如果不生成新的子流程而执行)会导致结果出现此时间表,并发5个并发请求(从#1到#5)。每个阻止循环事件的进程,每个请求都必须等待上一个请求完成才能被应答。
Time 0 10 20 30 40 50
#1 +----+
#2 +----+----+
#3 +----+----+----+
#4 +----+----+----+----+
#5 +----+----+----+----+----+
在生成新的子进程时,我期望,每个进程将由CPU上的另一个逻辑内核(我的有8个逻辑内核)同时处理。这个预计的时间表:
Time 0 10 20 30 40 50
#1 +----+
#2 +----+
#3 +----+
#4 +----+
#5 +----+
尽管如此,我在每次测试中都观察到了这个奇怪的结果:
Time 0 10 20 30 40 50
#1 +----+
#2 +----+----+
#3 +----+----+----+
#4 +----+----+----++
#5 +----+----+----+-+
尽管我假设会创建3个不同的池,但前3个请求的行为就像工作池处于饥饿状态。最后两个请求非常令人困惑,因为它们就像与请求#3并发工作一样。
我目前正在寻找以下方面的解释:
请注意,如果我添加另一个“快速”方法,如下所示:
@Get('fast')
async fast(): Promise<string> {
return 'Fast process ended.';
}
此方法不受并发运行的CPU密集型进程的影响,并且始终可以立即答复。
答案 0 :(得分:2)
我在机器上执行了测试用例,可以很好地检查一下。
节点版本:v8.11.2操作系统:macOs High Sierra 10.13.4,8核
child-process-test.js
const child_process = require('child_process');
for(let i=0; i<8; i++) {
console.log('Start Child Process:',i,(new Date()));
let worker_process = child_process.fork("cpu-intensive-child.js", [i]);
worker_process.on('close', function (code) {
console.log('End Child Process:', i , (new Date()), code);
});
}
cpu-tensive-child.js
const fs = require('fs');
// simulates a 10s-long process
let now = new Date().getTime();
let waittime = 10000; // 10 seconds
while (new Date().getTime() < now + waittime) { /* do nothing */ };
// send response to master process
// process.send({ result: 'Process ended' });
输出
您可以签入输出,所有过程的差异仅为10 sec
,您可以在计算机上执行此测试用例,并告诉我,可能会有所帮助。