最多创建 2 child/worker 个进程的 Express 服务器
Express server that creates maximum of 2 child/worker processes
我正在试验节点,它是 child_process 模块。
我的目标是创建最多 3 个进程(1 个主进程和可选的 2 个子进程)运行 的服务器。
我知道下面的代码可能不正确,但它显示了有趣的结果。
const app = require ("express")();
const {fork} = require("child_process")
const maxChildrenRuning = 2
let childrenRunning = 0
app.get("/isprime", (req, res) => {
if(childrenRunning+1 <= maxChildrenRuning) {
childrenRunning+=1;
console.log(childrenRunning)
const childProcess = fork('./isprime.js');
childProcess.send({"number": parseInt(req.query.number)})
childProcess.on("message", message => {
console.log(message)
res.send(message)
childrenRunning-=1;
})
}
})
function isPrime(number) {
...
}
app.listen(8000, ()=>console.log("Listening on 8000") )
我用 5*10^9 左右的数字发起 3 个请求。
30 秒后,我收到 2 条结果正确的回复。
CPU停止辛勤工作而闲着
出乎意料的是,在接下来的 1 分 30 秒后,1 个线程开始继续处理,仍在等待第 3 个请求,并在接下来的 30 秒后以正确答案完成。控制台日志显示如下:
> node index.js
Listening on 8000
1
2
{ number: 5000000029, isPrime: true, time: 32471 }
{ number: 5000000039, isPrime: true, time: 32557 }
1
{ number: 5000000063, isPrime: true, time: 32251 }
要么快速监听并偶尔检查一次挂起的请求,要么我的浏览器在挂起时每 x 次发送一次实际请求。谁能解释这里发生了什么以及为什么?我怎样才能正确地实现我的目标?
您的服务器代码的编写方式,如果您收到 /isprime
请求并且两个子进程已经 运行,您的 /isprime
请求处理程序什么都不做。它从不发送任何响应。您没有通过第一个 if
测试,之后什么也没有发生。因此,该请求将与客户端一起等待响应。根据客户端的不同,它可能最终会作为 dead/inactive 请求超时,客户端将关闭它。
一些客户端(如浏览器)可能会认为某些东西刚刚在网络中丢失,并且它们可能会通过再次发送请求来重试请求。我猜这就是您的情况。浏览器最终超时,然后重新发送请求。到它重试时,子进程少于两个 运行 因此它在重试时得到处理。
您可以通过转到 Chrome 调试器中的网络选项卡并查看浏览器向您的服务器发送的确切内容并查看第三个请求,查看它是否超时来验证浏览器是否正在自动重试这是浏览器重试请求。
请注意,此代码似乎只实现了部分,因为您最初启动了两个子进程,但您没有重用这些子进程。一旦它们完成并且您递减 maxChildrenRuning
,您的代码将启动另一个子进程。可能你真正想做的是跟踪你启动的两个子进程,当一个子进程完成时,将它添加到“可用子进程”数组中,这样当有新请求进来时,你可以只使用现有的子进程已经启动,但处于空闲状态。
您还需要在所有子进程已满时对传入请求进行排队,或者您需要向 http 请求发送某种错误响应。从不向传入请求发送 HTTP 响应是一种糟糕的设计,只会导致效率低下(连接停留的时间比实际需要的时间长得多,实际上从未完成任何事情)。
我正在试验节点,它是 child_process 模块。 我的目标是创建最多 3 个进程(1 个主进程和可选的 2 个子进程)运行 的服务器。 我知道下面的代码可能不正确,但它显示了有趣的结果。
const app = require ("express")();
const {fork} = require("child_process")
const maxChildrenRuning = 2
let childrenRunning = 0
app.get("/isprime", (req, res) => {
if(childrenRunning+1 <= maxChildrenRuning) {
childrenRunning+=1;
console.log(childrenRunning)
const childProcess = fork('./isprime.js');
childProcess.send({"number": parseInt(req.query.number)})
childProcess.on("message", message => {
console.log(message)
res.send(message)
childrenRunning-=1;
})
}
})
function isPrime(number) {
...
}
app.listen(8000, ()=>console.log("Listening on 8000") )
我用 5*10^9 左右的数字发起 3 个请求。 30 秒后,我收到 2 条结果正确的回复。 CPU停止辛勤工作而闲着 出乎意料的是,在接下来的 1 分 30 秒后,1 个线程开始继续处理,仍在等待第 3 个请求,并在接下来的 30 秒后以正确答案完成。控制台日志显示如下:
> node index.js
Listening on 8000
1
2
{ number: 5000000029, isPrime: true, time: 32471 }
{ number: 5000000039, isPrime: true, time: 32557 }
1
{ number: 5000000063, isPrime: true, time: 32251 }
要么快速监听并偶尔检查一次挂起的请求,要么我的浏览器在挂起时每 x 次发送一次实际请求。谁能解释这里发生了什么以及为什么?我怎样才能正确地实现我的目标?
您的服务器代码的编写方式,如果您收到 /isprime
请求并且两个子进程已经 运行,您的 /isprime
请求处理程序什么都不做。它从不发送任何响应。您没有通过第一个 if
测试,之后什么也没有发生。因此,该请求将与客户端一起等待响应。根据客户端的不同,它可能最终会作为 dead/inactive 请求超时,客户端将关闭它。
一些客户端(如浏览器)可能会认为某些东西刚刚在网络中丢失,并且它们可能会通过再次发送请求来重试请求。我猜这就是您的情况。浏览器最终超时,然后重新发送请求。到它重试时,子进程少于两个 运行 因此它在重试时得到处理。
您可以通过转到 Chrome 调试器中的网络选项卡并查看浏览器向您的服务器发送的确切内容并查看第三个请求,查看它是否超时来验证浏览器是否正在自动重试这是浏览器重试请求。
请注意,此代码似乎只实现了部分,因为您最初启动了两个子进程,但您没有重用这些子进程。一旦它们完成并且您递减 maxChildrenRuning
,您的代码将启动另一个子进程。可能你真正想做的是跟踪你启动的两个子进程,当一个子进程完成时,将它添加到“可用子进程”数组中,这样当有新请求进来时,你可以只使用现有的子进程已经启动,但处于空闲状态。
您还需要在所有子进程已满时对传入请求进行排队,或者您需要向 http 请求发送某种错误响应。从不向传入请求发送 HTTP 响应是一种糟糕的设计,只会导致效率低下(连接停留的时间比实际需要的时间长得多,实际上从未完成任何事情)。