在Node中的进程之间发送数据是否昂贵/高效?

Node允许你产生subprocess并在它们之间发送数据。 你可以使用它来执行一些阻止代码。

文档说:“这些孩子节点仍然是V8的全新实例,假设每个新节点至less有30ms启动和10MB内存,也就是说,你不能创build数千个节点。

我想知道它是否有效,我应该担心一些限制吗? 以下是示例代码:

//index.js var childProcess1 = childProcess.fork('./child1.js'); childProcess1.send(largeArray); childProcess1.once('message', function(formattedData) { console.log(formattedData); return false; }); //child1.js process.on('message', function(data) { data = format(data); //do smth with data, then send it back to index.js try{ process.send(data); return false; } catch(err){ console.log(err); return false; } }); 

该文档告诉你,开始新的节点进程是相对昂贵的。 fork()每次你需要做工作是不明智的。

相反,您应该维护一个长期运行的工作进程池 – 就像线程池一样。 在主进程中排队工作请求,并在空闲时将其分派给下一个可用的工作人员。

这给我们留下了关于节点的IPC机制的性能概况的问题。 当fork() ,节点会自动在subprocess上设置一个特殊的文件描述符。 它通过读取和写入由行分隔的JSON来使用它在进程之间进行通信。 基本上,当你process.send({ ... }) ,节点JSON.stringify s它并写入序列化的string到fd。 接收过程读取这个数据直到遇到一个换行符,然后JSON.parse s它。

这必然意味着性能将高度依赖于您在进程之间发送的数据的大小。

我已经粗略地进行了一些testing,以更好地了解这个性能是什么样子的。

首先,我向工作人员发送了一个N字节的消息,该消息立即以相同长度的消息作出响应。 我在我的四核超线程i7上用1到8个并发工作者来试试这个。

图形

我们可以看到,至less有两名工人对原料吞吐量有利,但超过两名工人并不重要。

接下来,我向工作人员发送了一个空的消息,立即回复了一个N字节的消息。

图形

令人惊讶的是,这没有什么区别。

最后,我尝试向工作人员发送一个N字节的消息,这个消息立即回复了一个空的消息。

图形

有趣的是,性能不会随着更大的消息而迅速降低。

小贴士

  • 接收大消息比发送消息要贵一些。 为获得最佳吞吐量,主进程不应发送大于1 kB的消息,并且不应接收大于128字节的消息。

  • 对于小消息来说,IPC开销大约是0.02ms。 这足够小,在现实世界中是无足轻重的。

认识到消息的序列化是一个同步的阻塞调用是很重要的。 如果开销太大,则在发送消息时,整个节点进程将被冻结。 这意味着I / O将会饿死,您将无法处理任何其他事件(如传入的HTTP请求)。 那么通过节点IPC可以发送的最大数据量是多less?

图形

事情真的超过32 kB的讨厌。 (这些是每个消息;双重获取往返开销。)

故事的寓意是你应该:

  • 如果input大于32 kB,请find让工作人员获取实际数据集的方法。 如果要从数据库或其他networking位置提取数据,请在工作人员中执行请求。 没有主人获取数据,然后尝试发送消息。 这个信息应该只包含足够的信息让工作人员完成工作。 想想像函数参数那样的消息。

  • 如果输出大于32 kB,请find让工作人员在消息外传递结果的方法。 写入磁盘或将套接字发送给工作人员,以便您可以直接从工作进程作出响应。

这实际上取决于您的服务器资源和需要启动的节点数量。

根据经验:

  • 尽量重复使用跑步的孩子 – 这将节省你30毫秒的启动时间
  • 不要开始无限​​制的孩子数量(例如每个请求1个) – 您不会耗尽内存

消息本身相对较快,我相信。 虽然看到一些指标会很好。

另外,请注意,如果您有单个CPU或正在运行集群(使用所有可用内核),则没有多大意义。 您的CPU容量仍然有限,切换上下文比运行单个进程要贵。