Perl 为什么';我的父进程不能看到子进程';在它退出之前,输出是什么?

Perl 为什么';我的父进程不能看到子进程';在它退出之前,输出是什么?,perl,ipc,Perl,Ipc,考虑以下脚本: 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, $

考虑以下脚本:

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);
}
使用IO::File;
$| = 1;
my($handle,$pid)=myPipe();
如果($pid==0){
打印“$$”;
睡眠5;
出口
}
打印“子项:…”\n;
烟斗{
my$handle=新IO::File();
my$pid=打开($handle,“-|”);
返回($handle,$pid);
}

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

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

  • \n
    添加到子消息的末尾,这通常会导致管道冲洗
  • $|
    设置为1,这将导致当前选定的文件句柄自动刷新
  • 使用
    IO::Handle
    并调用
    $Handle->flush
  • 使用
    IO::Handle
    并设置
    $Handle->autoflush=1
在某些(大多数?)系统上,管道默认使用I/O缓冲。放

$handle->autoflush(1);
您的
myPipe
函数中的语句

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



更新:在测试代码(Cygwin、perl 5.10.0、YMMV)时,我发现问题在于子输出中缺少换行符,而不是在创建管道时是否显式打开自动刷新。

有两个问题。首先,子进程正在缓冲其输出;第二,父进程使用
操作符,它会一直阻塞,直到有完整的行可用,或者直到文件结束

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

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;
}

冲洗管道不是由内核处理的。缓冲是一个用户特性!那不太对。如果打开自动刷新,则句柄为非缓冲(每次打印后刷新);如果关闭自动刷新且句柄打开到tty,则为行缓冲(每次换行后刷新);否则为块缓冲(当缓冲区(通常为几kB)已满时刷新)。Re:update——请参阅Sean的答案。换行符之所以重要,不是因为缓冲,而是因为父对象中的readline/
操作需要在换行符返回之前读取它——EOF除外:)@hobbs——感谢您的澄清。在这个特定的示例中,在父对象中调用
,直到输入中有一个换行符或输入关闭后才会返回。所以新线仍然是个问题,但原因和我想的稍有不同。我想你可以用
$/
做些时髦的事。谢谢你的详尽回答。后来我意识到,如果使用,将需要一个新行字符。