【问题标题】:How to kill the child process with fork implementation in nodeJS and how to be sure that process is indeed killed after execution?如何在nodeJS中使用fork实现杀死子进程以及如何确保该进程在执行后确实被杀死?
【发布时间】:2020-11-28 16:51:27
【问题描述】:

我需要执行一些用不同 js 文件编写的代码。我在 child_process 模块中使用 fork 方法。在单个 API 调用中将有多达 1000 个请求来执行该文件代码。有了这么多的请求,杀死正在执行子文件的进程就变得很重要了。

我的查询是:

  1. fork 方法生成的子进程是在执行代码后自行杀死还是我们必须显式杀死它们(如果是,我们如何实现)

fork 和 childprocess 中有很多问题和答案,但 NodeJS 没有,我无法从这些答案中获得任何帮助。

以我有限的知识,我编写了示例代码并试图杀死在子节点中运行的进程。这适用于第一个 API 请求,但是当第二个 API 请求到来时。节点应用程序崩溃。

我的代码:

master.js

const fork = require('child_process').fork;
const cp1 = fork('./child1.js');

const app = require('express')();

function timer(ms) {
   return new Promise(resolve => setTimeout(resolve, ms));
 }

app.get('/forktesting',(req, res)=>{
   let num = [45, 5, 48, 91, 74, 3, 82];
   try {
      for (let index = 0; index < num.length; index++) {
         await timer(1000);
         cp1.send('test');
   }
   cp1.on('message', (msg)=>{
      console.log(`recieving message code in parent process: ${msg.val}`);
   });
   cp1.on('exit',(msg=>{
      console.log(`recieving exit code in parent process: ${msg}`);
   }));
   console.log('last line of API call');
} catch (error) {
      console.log({'error' : error});
      res.send({"code": 500, "status":"error"});
   }
});

app.listen(8081, ()=>{ console.log(`listening to 8081`);})

child1.js

process.on('message', async(message)=>{
    console.log(`in message child: ${message}`);
    setTimeout(() => {
        process.send({ val: "from child"});
        console.log(`child pid: ${process.pid}`);
        process.kill(process.pid);
    }, 5000);
})

第一次 API 调用中的响应 工作正常

错误

注意:显示正确的实现将非常有帮助

在第二个文件(child1.js)中,我正在调用不同的系统并等待它们的响应,收到响应后我会将其发送到父进程。

Edit2:在 cp1.send() 周围添加了 for 循环,以表明通过单个 API 调用将有多个子进程的分叉,并添加了 try catch 块。 我根据实际场景的需要添加了 for 循环进行分叉。所以同一个文件会被分叉很多次,我已经在数组中显示了 3 个项目,但之后会是 1000 个,这将从 DB 中获取。场景是:每次调用 API 时,我都必须 fork 多次,并且该 API 会被用户频繁使用,因此会有多个用户访问它。随着每个 API 命中,将添加侦听器,因此我的许多侦听器将听到单个响应,这也会在侦听器计数的某个阈值超过之后产生问题。所以,event.once 的实现会很好,但我希望孩子的响应计数也因此可能必须与监听器一起去监听每个分叉孩子的响应。

Edit1:我在子进程中删除了process.kill(process.pid),并在 5 秒内点击了两次。我得到了两次响应,这不是我想要的功能。下图显示了控制台输出。

我应该只从那个分叉的进程中得到一个响应。使用 remove process.kill(process.pid),每次调用此 API 都会增加响应计数。

照片显示原始问题和编辑 1 的日志

【问题讨论】:

  • 您不想杀死任何这些进程。完成后你想exit子进程。
  • 您只在服务器启动时分叉进程一次,而不是每个请求一次。由于您的子进程在被第一个请求杀死后停止,因此它不再可用于第二个请求。不确定您实际想要达到的目标
  • "fork 方法生成的子进程在执行代码后是否会杀死自己" - 是的,每个进程在完成时会自行停止(退出),即当它认为它是自己完成的。 (当然,这可能永远不会)。
  • "使用单个 API 调用会有多个子进程的分叉" - 不,这仍然没有发生。当服务器启动时,您只对子进程进行一次分叉,然后每当您的服务器收到请求时向它发送(多个)消息。仍然只有一个子进程,没有多个分叉,也不需要杀死任何东西。
  • "this 另有说明" - 不,它和我说的完全一样。一个进程在被杀死或决定退出时停止拥有,大多数 - 但不是所有 - 进程都会这样做。无论如何,您控制子进程,所以首先您需要决定 何时应该退出。除了“我正在调用不同的系统并等待他们的响应”之外,您还没有告诉我们子进程应该做什么,但这并没有t 需要一个子进程本身。

标签: javascript node.js


【解决方案1】:

在child1.js中你要使用:

process.on('message', async(message)=>{
    console.log(`in message child: ${message}`);
    setTimeout(() => {
        process.send({ val: "from child"});
        console.log(`child pid: ${process.pid}`);
        process.exit();
    }, 5000);
})

最大的不同是使用process.exit(); 让孩子自行终止。它将返回一个在 process.exit() 中传递的整数; (默认为 0)。

还将你的 master.js 更改为:

const fork = require('child_process').fork;
var cp1 = fork('child1.js');

const app = require('express')();

app.get('/forktesting',(req, res)=>{
  cp1 = fork('child1.js');
   cp1.send('test');
   cp1.on('message', (msg)=>{
      console.log(`recieving message code in parent process: ${msg.val}`);
   });
   cp1.on('exit',(msg)=>{
      console.log(`recieving exit code in parent process: ${msg}`);
   });
   console.log('last line of API call');
});

app.listen(8081, ()=>{ console.log(`listening to 8081`);})

当您最初使用var cp1 = fork('child1.js'); 生成子进程时,它会自行终止,因此您必须在下次用户或程序需要时使用cp1 = fork('child1.js'); 生成另一个子进程。

还要回答您的问题,子进程不会自行终止,您必须告诉它终止,similar question here

【讨论】:

  • 我没弄明白,请指教。我用 process.exit() 替换了 process.kill(process.pid) ,抛出错误'“pid”参数必须是数字类型。接收到的类型未定义'。当我将process.kill(process.pid) 替换为process.exit(0) 时,当API 被两次命中时,我面临着同样的问题。
  • 好的,我想通了,我现在就编辑我的答案。
【解决方案2】:

如果您在终止进程之前的 5 秒超时内进行第二次调用,它将起作用。您的问题是您杀死了该进程并尝试在之后调用它。如果你查看你的控制台,你会看到退出事件被调用了。

删除

process.kill(process.pid);

它应该可以工作。即

process.on('message', async(message)=>{
    console.log(`in message child: ${message}`);
    setTimeout(() => {
        process.send({ val: "from child"});
        console.log(`child pid: ${process.pid}`);
        // process.kill(process.pid); // terminates the process. Cannot use it after terminated.
    }, 5000);
})

我不知道你想要达到什么目的。

const cp1 = fork('./child1.js');

在 api 中,它应该为每个请求调用脚本。

const fork = require('child_process').fork;


const app = require('express')();

app.get('/forktesting',(req, res)=>{
    const cp1 = fork('./child1.js'); // fork for each request.
   cp1.send('test');
   cp1.on('message', (msg)=>{
      console.log(`recieving message code in parent process: ${msg.val}`);
   });
   cp1.on('exit',(msg=>{
      console.log(`recieving exit code in parent process: ${msg}`);
   }));
   console.log('last line of API call');
});

app.listen(8081, ()=>{ console.log(`listening to 8081`);})

这将为每个请求创建一个新进程。

如果您确实为每个请求创建了一个新进程,则不要在 settimeout 中删除进程终止。即保持

process.kill(process.pid);

查看https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options 了解更多信息。

【讨论】:

  • 那没用,我执行您的建议。我已编辑问题以在输出中显示您的实现及其效果
  • 如果您需要为每个请求多次分叉,然后输入 const cp1 = fork('./child1.js');在你循环中
猜你喜欢
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
  • 2011-08-17
  • 2022-11-23
  • 2014-09-30
  • 2011-09-23
  • 1970-01-01
  • 2011-09-09
相关资源
最近更新 更多