【问题标题】:Why doesn't my parent process see the child's output until it exits?为什么我的父进程在退出之前看不到子进程的输出?
【发布时间】:2011-01-21 13:35:36
【问题描述】:

考虑以下脚本:

use IO::File;
$| = 1;
my ($handle, $pid) = myPipe();
if ($pid == 0) {
  print "$$";
  sleep 5;
  exit;
}

print "child: ".<$handle>."\n";

sub myPipe {
  my $handle = new IO::File();
  my $pid = open($handle, "-|");
  return ($handle, $pid);
}

在这种情况下,“child:”消息在进程启动后的 5 秒内不会出现。如果我从分叉的孩子那里删除睡眠呼叫,那么它会立即打印。为什么分叉的孩子必须退出管道才能冲洗到父母?

【问题讨论】:

    标签: perl ipc


    【解决方案1】:

    冲洗管道不会按任何固定时间表进行。您可以强制管道刷新的唯一两种方法是退出子进程(这就是您现在正在做的事情),或者显式调用flush。您可以通过执行以下任何操作使您的句柄在 perl 中刷新:

    • 在子消息的末尾添加\n,这(通常)会导致管道刷新
    • $| 设置为 1,这会导致当前选定的文件句柄自动刷新
    • 使用IO::Handle 并调用$handle-&gt;flush
    • 使用IO::Handle 并设置$handle-&gt;autoflush = 1

    【讨论】:

    • 刷新管道不是由内核处理的。缓冲是用户级功能!
    【解决方案2】:

    在某些(大多数?)系统上,管道默认使用 I/O 缓冲。放一个

    $handle->autoflush(1);
    

    myPipe 函数中的声明。

    但是即使关闭了缓冲,Perl 仍然不会刷新,除非在换行符之后。因此,您可能还希望您的子进程在输出中包含换行符。


    更新: 测试您的代码(Cygwin、perl 5.10.0、YMMV),我发现问题在于子输出中缺少换行符,而不是在管道已创建。

    【讨论】:

    • 这不太对。如果 autoflush 打开,句柄是非缓冲的(每次打印后刷新),如果 autoflush 关闭并且句柄打开到 tty,句柄是行缓冲的(在每个换行后刷新),并且是块缓冲的(在缓冲区时刷新) ,通常为几 kB,已满)否则。
    • 回复:更新——见肖恩的回答。换行的重要性不是因为缓冲,而是因为父中的 readline/&lt;&gt; 操作需要在返回之前读取换行——除了在 EOF :)
    • @hobbs - 感谢您的澄清。在此特定示例中,在输入中有换行符或输入关闭之前,对父级中的 &lt;$handle&gt; 的调用不会返回。所以换行符仍然是问题,但原因与我想象的略有不同。我想你可以用$/ 做一些时髦的事情。
    【解决方案3】:

    有两个问题。首先,子进程正在缓冲它的输出;其次,父进程正在使用&lt;&gt; 运算符,它会阻塞直到有完整的行可用,或者直到文件结束。

    因此,获得预期结果的一种方法是让子进程在写入后立即关闭其输出流:

    if ($pid == 0) {
        print "$$";
        close STDOUT;
        sleep 5;
        exit;
    }
    

    另一种方法是在子进程的输出中添加换行符,然后刷新流:

    if ($pid == 0) {
        print "$$\n";
        STDOUT->flush;  # "close STDOUT;" will work too, of course
        sleep 5;
        exit;
    }
    

    刷新是必要的,因为管道(通常)是无缓冲的,而不是像连接到终端的流通常那样是行缓冲的。

    第三种选择是将子进程的输出流设置为自动刷新:

    if ($pid == 0) {
        $| = 1;
        print "$$\n";
        sleep 5;
        exit;
    }
    

    【讨论】:

    • 感谢您的详尽回答。后来我意识到使用 需要一个换行符。
    猜你喜欢
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 2020-03-21
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多