首页 > 解决方案 > Express 服务器,最多可创建 2 个子/工作进程

问题描述

我正在试验节点,它是 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'ish 数字发起 3 个请求。30 秒后,我收到 2 个结果正确的回复。CPU 停止努力工作并进入空闲状态 令人惊讶的是,在接下来的 1 分 30 秒后 1 个线程开始继续,仍然挂起,第三个请求并在接下来的 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 次发送一次实际请求。谁能解释这里发生了什么以及为什么?我怎样才能正确地实现我的目标?

标签: javascriptnode.jsexpressforkchild-process

解决方案


你的服务器代码的编写方式,如果你收到一个/isprime请求并且两个子进程已经在运行,你的请求处理程序/isprime什么也不做。它从不发送任何响应。你没有通过第一次if测试,然后什么也没有发生。因此,该请求将与客户端一起等待响应。根据客户端的不同,它最终可能会作为无效/非活动请求超时,并且客户端会将其关闭。

一些客户端(如浏览器)可能会假设某些内容刚刚在网络中丢失,他们可能会通过再次发送来重试请求。我猜这就是你的情况。浏览器最终超时,然后重新发送请求。到它重试时,运行的子进程少于两个,因此它在重试时得到处理。

您可以通过转到 Chrome 调试器中的网络选项卡并查看浏览器向您的服务器发送的确切内容并查看第三个请求,查看它是否超时并查看是否是浏览器重试请求来验证浏览器是否正在自动重试。


请注意,此代码似乎只是部分实现,因为您最初启动了两个子进程,但您没有重用这些子进程。一旦它们完成并且您递减maxChildrenRuning,您的代码将启动另一个子进程。可能您真正想要做的是跟踪您启动的两个子进程,当一个子进程完成时,将其添加到“可用子进程”数组中,这样当有新请求进来时,您可以只使用现有的子进程那已经开始了,但是空闲。

您还需要在所有子进程已满时对传入请求进行排队,或者您需要向 http 请求发送某种错误响应。从不向传入请求发送 http 响应是一种糟糕的设计,只会导致效率极低(连接挂起的时间比需要的时间长得多,但实际上从未完成任何事情)。


推荐阅读