【问题标题】:How to send huge amounts of data from child process to parent process in a non-blocking way in Node.js?如何在 Node.js 中以非阻塞方式将大量数据从子进程发送到父进程?
【发布时间】:2014-06-27 11:03:40
【问题描述】:

我正在尝试将一个巨大的 json 字符串从子进程发送到父进程。我最初的方法如下:

孩子: process.stdout.write(myHugeJsonString);

父母: child.stdout.on('data', function(data) { ...

但现在我read 认为process.stdout 正在阻塞:

process.stderrprocess.stdout 与 Node 中的其他流不同 写入它们通常是阻塞的。

  • 它们在引用常规文件或 TTY 文件描述符的情况下被阻塞。
  • 如果他们指的是管道:
    • 它们在 Linux/Unix 中阻塞。
    • 与 Windows 中的其他流一样,它们是非阻塞的。

documentation for child_process.spawn 表示我可以使用pipe 选项在子进程和父进程之间创建一个管道。但是在 Linux/Unix 中管道不是阻塞我的标准输出(根据上面引用的文档)?

好的,Stream object选项呢?嗯,看来我可以与子进程共享一个指向套接字的可读或可写流。这会是非阻塞的吗?我将如何实现它?

所以问题来了:如何在 Node.js 中以非阻塞方式将大量数据从子进程发送到父进程? 跨平台解决方案会非常简洁,非常感谢带有解释的示例。

【问题讨论】:

  • 您是否尝试过使用stdio: 'ipc' 并以这种方式发送/接收消息?
  • @mscdex 还没有。这会导致非阻塞数据传输吗? child.send 在我看来也被阻止了。文档说请注意,父子节点上的 send() 方法是同步的 - 不建议发送大块数据(可以使用管道,参见 child_process.spawn)。 我是完全糊涂了。
  • 您找到解决方案了吗?我正在尝试使用额外的 stdio 管道(fd >=4)从 .spawn() 流式传输,但找不到让我的子进程将 fd 作为流打开的方式。

标签: node.js child-process


【解决方案1】:

我在 *nix 上使用的一个巧妙技巧是 fifo 管道 (http://linux.about.com/library/cmd/blcmdl4_fifo.htm)。这允许子级写入类似文件的文件,而父级可以读取相同的文件。该文件实际上并不在 fs 上,因此您不会遇到任何 IO 问题,所有访问都由内核本身处理。但是......如果你想要它跨平台,那是行不通的。 Windows 上没有这样的东西(据我所知)。

请注意,您定义了管道的大小,如果您(从子级)写入的内容没有被其他东西(从父级)读取,那么当管道已满时,子级将阻塞。这不会阻塞节点进程,它们将管道视为普通文件流。

【讨论】:

  • 谢谢。虽然我正在寻找一个跨平台的解决方案(用这个规范更新了我的问题)。希望您的回答对其他人有所帮助。
【解决方案2】:

我遇到了类似的问题,我认为我有一个很好的解决方案,方法是在生成子进程时设置管道并使用生成的文件描述符将数据双工传输到客户端。

How to transfer/stream big data from/to child processes in node.js without using the blocking stdio?

显然,您可以使用fs 与文件描述符进行流式传输:

How to stream to/from a file descriptor in node?

【讨论】:

  • 感谢 Bartvds,但不是在 Linux 上设置管道阻塞(根据文档)吗?你能以某种方式证明你的方法导致子进程和父进程之间的非阻塞数据传输吗?
  • 文档对阻止 pipe 只字未提。它确实这样说:“请注意,父子节点上的 send() 方法是同步的 - 不建议发送大块数据(可以使用管道,请参阅 child_process.spawn”
  • Here the docs say 关于process.stdout 流在引用管道时被阻塞。正是这部分文档(这似乎与您在评论中引用的部分相矛盾)让我很困惑。如果你能澄清这一点,那就太好了!
  • 我读到了,但是这些管道并不是标准输出中描述的特殊情况。但这有点令人困惑,我没有办法证明这一点,所以我专门为此发布了another question
【解决方案3】:

child_process.spawn 的文档说我可以使用 pipe 选项在子进程和父进程之间创建一个管道。但是在 Linux/Unix 中管道不是阻塞我的标准输出(根据上面引用的文档)?

  1. 没有。上面的文档说 stdout/stderr,绝不是说“所有管道”。

  2. stdout/stderr 阻塞并不重要。为了使管道阻塞,它需要填满,这需要大量数据。为了填满,另一端的读者阅读速度必须比你写的慢。但是......你是另一端,你写了父进程。因此,只要您的父进程正常运行,它就应该从管道中读取数据。

一般来说,阻止孩子是一件好事。如果其生成数据的速度比父级处理的快,则最终只有两种可能性: 1. 它阻塞,因此停止生成数据,直到父级赶上 2. 它产生的数据多于父进程可以消耗的数据,并将该数据缓存在本地内存中,直到达到 v8 内存限制,进程中止

如果需要,您可以使用 stdout 发送 json 1)

如果需要,您可以使用新的“管道”发送 json 2)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-23
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    • 2016-07-28
    • 1970-01-01
    相关资源
    最近更新 更多