0

我遇到了在 MacOS X Mountain Lion 下产生大量进程(200)的问题(尽管我确信这个问题不是特定于版本的)。我正在做的是启动进程(在我的测试中是 /bin/cat),它们的 STDIN、STDOUT 和 STDERR 连接到管道——管道的另一端是生成(父)进程。

父进程将数据写入进程的 STDIN,然后通过管道传送到 [/bin/cat] 子进程,子进程又将数据从 STDOUT 中吐出并由父进程读取。/bin/cat 仅用于测试。

我实际上是在使用 kqueue 在 STDIN 管道中有可用空间时收到通知。当 kqueue 通过 EVFILT_WRITE 事件通知您有可用空间时,该事件还会准确地告诉您可以写入多少字节而不会阻塞。

这一切都很好,我可以轻松地生成 100 个子 (/bin/cat) 进程,并且所有内容都流过管道而不会阻塞(整天)。但是,当我将进程数增加到 200 个时,当单个 kqueue 服务线程阻塞对一个 STDIN 管道的 write() 调用时,一切都停止了。该事件表示有 16384 个字节可用(基本上是一个空管道),但是当程序尝试将 16384 个字节准确写入管道时,无论如何 write() 都会阻塞。

最初我以为我遇到了最大值。打开文件问题,但我已经将打开文件的 ulimit 提升到 8192,所以这不是问题。我从一些谷歌搜索中发现,在 OS X 上,STDIN/STDOUT/STDERR 实际上不是“文件”(或“管道”),而是实际上是设备。当进程挂起时,在命令行上运行 lsof 也会挂起,并显示无法 stat() 文件系统的警告:

lsof: WARNING: can't stat() hfs file system /
      Output information may be incomplete.
      assuming "dev=1000008" from mount table

一旦我终止该进程, lsof 就会完成。这强化了 STDIN/OUT/ERR 实际上是设备的概念,我遇到了某种限制。

有谁知道我遇到了什么限制,例如可以创建的“设备”数量是否有限制?这可以以某种方式增加吗?

4

1 回答 1

0

只是在这里回答我自己的问题。这似乎与 MacOS X 如何将管道从 16K 动态扩展到 32K 到 64K(等等)有关。我的基本解决方法是防止管道膨胀。看来,每当您完全填满管道时,操作系统都会将其扩展。因此,当 kqueue 触发我可以写入管道并指示我有 16384 字节可写入时,我只需写入 16384 - 1 字节。基本上,无论它告诉我什么可用,我最多写(可用 - 1)个字节。这可以防止管道扩展,并防止我的代码遇到对管道的 write() 会阻塞的情况(即使管道是非阻塞的)。

于 2013-09-12T02:44:04.720 回答