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
$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——感谢您的澄清。在这个特定的示例中,在父对象中调用
,直到输入中有一个换行符或输入关闭后才会返回。所以新线仍然是个问题,但原因和我想的稍有不同。我想你可以用$/
做些时髦的事。谢谢你的详尽回答。后来我意识到,如果使用,将需要一个新行字符。