【问题标题】:managing multiple node child processes管理多个节点子进程
【发布时间】:2017-06-24 00:22:11
【问题描述】:

如何管理多个已分叉的并发子进程?

在本例中,start_child() 可以被多次调用,并且每次调用都可以无限期地运行。当像这样分叉任意数量的子进程时,我如何与每个单独的子进程通信/寻址?假设我有 3 个分叉的子进程正在运行,它们会无限期地运行,但我想杀死(或发送消息)2 号子进程。我该怎么做?

如果调用stop_child(),它会杀死所有当前正在运行的子进程。如何重构此代码,以便可以在单个子进程上调用 stop_child()

let app     = require('express')();
let server  = require('http').Server(app);
let io      = require('socket.io')(server);
let fork    = require('child_process').fork;

server.listen(80);

app.get('/', function(request, response) {
    response.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket) {
    socket.on('start_child', function () {
        start_child();
    });

    socket.on('stop_child', function () {
        child.kill();
    }
}

function start_child() {
    child = fork('./child_script.js');

    //conditional logic to either run
    //start_child() again or let it end
}

更新

我根据一些 cmets 进行了尝试。但是,如果我启动 3 个进程然后调用,例如,child[0].kill(),我会收到一个错误:Cannot read property 'kill' of undefined。我猜我的问题是我没有正确地将i 变量传递给io.on() 调用:

let app     = require('express')();
let server  = require('http').Server(app);
let io      = require('socket.io')(server);
let fork    = require('child_process').fork;
let i       = 0;
let child   = [];

server.listen(80);

app.get('/', function(request, response) {
    response.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket) {
    socket.on('start_child', function (i) {
        start_child(i++);
    });

    //this is hard coded just for testing
    socket.on('stop_child', function () {
        child[0].kill();
    }
}

function start_child(i) {
    child[i] = fork('./child_script.js');

    //conditional logic to either run
    //start_child() again or let it end
}

更新 #2

好的,我发现我需要从客户端发送递增变量,通过来自emit 调用的对象传递。现在当我打电话给child[0].kill() 时没有错误。问题是子进程没有被杀死:

server.js

let app     = require('express')();
let server  = require('http').Server(app);
let io      = require('socket.io')(server);
let fork    = require('child_process').fork;

server.listen(80);

app.get('/', function(request, response) {
    response.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket) {
    socket.on('start_child', function (count) {
        let num = count.count;
        start_child(num);
    });

    //this is hard coded just for testing
    socket.on('stop_child', function (count) {
        let num = count.count;
        child[num].kill();
    }
}

function start_child(num) {
    child[num] = fork('./child_script.js');

    //conditional logic to either run
    //start_child() again or let it end
}

index.html

$(function () {
    let socket  = io();
    let i       = 0;

    $('#start').on('click', function () {
        socket.emit('start_child', {"count": i++});
    });

    $('#stop').on('click', function () {
        //the count is hard coded here just for testing purposes
        socket.emit('stop_child', {"count": 0});
    });
});

最终更新 - 有解决方案

解决方案#2(在此上方)实际上是解决方案。之后我遇到的问题(child.kill() 调用似乎没有做任何事情)是由我遗漏的一段代码引起的(在代码注释中:'条件逻辑要么运行 start_child()再次或让它结束')。

这就是里面的东西:

if (condition) {
    setTimeout(start_child, 5000);
} else {
    console.log('this child process has ended');
}

这就是我将其更改为的内容(基本上,我只需将递增变量传递给start_child() 函数,以便它在重新启动时在child 数组中具有相同的位置):

if (condition) {
    setTimeout(function() {
        start_child(num)
    }, 5000);
} else {
    console.log('this child process has ended');
}

【问题讨论】:

  • 您的服务器在什么操作系统上运行,您的 child_script 在做什么。它在child.kill() 的文档中这样说:请注意,虽然该函数被称为 kill,但传递给子进程的信号实际上可能不会终止该进程。 你应该还要记录child.on('error', ...),以防传递终止消息时出错。
  • 目前在 Windows 上的 Cygwin 环境中运行。

标签: node.js child-process


【解决方案1】:

fork() 返回一个 ChildProcess 对象,该对象在该对象上具有用于与该进程进行进程间通信的方法和事件。因此,您必须在调用 start_child() 时保存每个 ChildProcess 对象,然后使用适当的对象与其他进程进行通信。

您可以看到 ChildProcess 对象here 的事件和方法。还有很多代码示例。

【讨论】:

  • 我了解fork() 返回一个 ChildProcess 对象,并且我已阅读文档。我只是不清楚如何处理特定的子对象(当多个子对象被分叉时),或者我需要如何重构示例代码来实现这一点。
  • @CJG - 很难理解问题所在。如果您打开 5 个子进程,则可以将它们保存在一个数组中。为了与第一个通信,您从数组的第一个元素中获取 ChildProcess 对象,然后使用该特定的 ChildProcess 对象与该特定子通信。
  • @CJG - 您是在尝试从父母向特定孩子发送消息,还是从一个特定孩子向另一个特定孩子发送消息?
  • @CJG - 您的 start_child() 函数应该将它打开的每个子元素放入一个位于更高范围内的数组中,以便您以后想要与其中一个子元素通信时可以访问该数组进程。
  • 我正在尝试将消息从父母发送给特定的孩子。具体来说,我正在尝试将child.kill() 发送给特定的孩子。如果我启动两个进程,然后只想杀死第一个,我该怎么做?我更新了我的问题,我尝试按照您所说的进行操作,但仍然不太正确。
【解决方案2】:

为了向子进程发送消息,请使用以下示例:

父.js

**

const { fork } = require('child_process');
const forked = fork('child.js');
forked.on('message', (msg) => {
  console.log('Message from child', msg);
});
forked.send({ hello: 'world' });

**

child.js

process.on('message', (msg) => {
  console.log('Message from parent:', msg);
});

let counter = 0;

setInterval(() => {
  process.send({ counter: counter++ });
}, 1000);

更多信息请参考这篇文章:

https://medium.freecodecamp.com/node-js-child-processes-everything-you-need-to-know-e69498fe970a

【讨论】:

  • 我知道如何在父母和孩子之间来回发送消息。我不知道当父母有多个孩子时如何向特定孩子发送消息。
  • 您需要记住父端的子节点,例如将子对象存储在数组中,然后调用适当的子对象方法
  • 你能举个简单的例子吗?我需要能够为特定的孩子拨打kill()。由于当前编写的代码,如果我调用child.kill(),那么所有子进程都会被杀死。我知道每个子节点都必须在父端记住;我只是不太确定如何使用这段代码来做到这一点。
  • 我不太了解您的确切要求,但我认为可以做到以下几点:var array = {};数组["child1"] = forked1;数组[“child2”] = forked2;数组["child3"] = forked3;数组["child1"].kill();
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-14
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 2019-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多