回复子进程中的消息

时间:2017-07-16 01:01:39

标签: javascript node.js

我正在寻找一种有效的方式来回复发送给子进程的消息。目前,我使用以下代码:

 const { fork } = require('child_process');
 const child = fork(path.join(__dirname, 'sub.js'));

 async function run() {
   console.log('Requesting status....');
   child.send('status');
   const status = await awaitMessage(child);
   console.log(status);
 }

 function awaitMessage(childProcess) {
   return new Promise((resolve) => {
     childProcess.on('message', (m) => {
       resolve(m);
     });
   });
 }

此代码的问题在于,每次调用awaitMessage()函数时都会创建一个新的事件侦听器,这很容易导致内存泄漏。是否有一种优雅的方式来接收来自子进程的回复?

1 个答案:

答案 0 :(得分:0)

这实际上并不容易出现内存泄漏问题。因为泄漏是应该被释放的东西(根据垃圾收集器的规则),但不是。在这种情况下,您已经将一个与事件处理程序挂钩的承诺仍然可以被调用,因此系统根本无法知道您打算将其释放。

因此,系统保留了您的代码要求保留的内容。它是你的代码如何工作的结果,它保留了awaitMessage()中创建的每一个承诺,同时也解雇了一堆额外的事件处理程序。因为你保留了事件监听器,所以垃圾收集器会看到承诺仍然是可以访问的#34;通过该侦听器,因此即使没有外部引用也不会也不应该删除该承诺(根据Javascript垃圾收集器的规则)。

如果您要在promise中添加事件侦听器,则必须在promise解析时删除该事件侦听器,以便最终释放promise。承诺在Javascript中不是魔术对象,它只是一个常规对象,所以只要你有一个可以被实时事件监听器引用的对象,该对象就不能被垃圾收集。

此外,如果您连续两次调用awaitMessage(),这将受到竞争条件的影响,因为两个承诺将响应下一条消息。一般来说,这不是一个好的设计方法。如果您想等待消息,那么您必须以某种方式标记您的消息,以便您知道哪个消息响应是您正在等待的实际消息响应以避免您的竞争条件,并且您必须在获得后删除事件监听器你的消息。

为避免因听众积累而造成内存累积,您可以这样做:

 function awaitMessage(childProcess) {
   return new Promise((resolve) => {
     function handleMsg(m) {
       childProcess.removeListener(handleMsg);
       resolve(m);
     }
     childProcess.on('message', handleMsg);
   });
 }