【发布时间】:2012-04-19 05:46:18
【问题描述】:
我浏览了open3 的文档,这是我无法理解的部分:
如果您尝试从孩子的 stdout writer 和他们的 stderr 读取 作家,你会遇到阻塞问题,这意味着你会想要 使用 select() 或 IO::Select,这意味着你最好使用 sysread() 而不是 readline() 用于普通的东西。
这是非常危险的,因为您可能会永远阻塞。它假设它是 与 bc 之类的东西交谈,既写信又读 从中。这可能是安全的,因为您“知道”命令像 bc 将一次读取一行并一次输出一行。程式 然而,就像首先读取整个输入流的排序一样, 很容易造成死锁。
所以我尝试了open3,希望能更好地了解它。这是第一次尝试:
sub hung_execute {
my($cmd) = @_;
print "[COMMAND]: $cmd\n";
my $pid = open3(my $in, my $out, my $err = gensym(), $cmd);
print "[PID]: $pid\n";
waitpid($pid, 0);
if(<$err>) {
print "[ERROR] : $_" while(<$err>);
die;
}
print "[OUTPUT]: $_" while (<$out>);
}
有趣的是,我必须在这里初始化$err。
无论如何,这只是在我 execute("sort $some_file"); 时挂起,因为 $some_file 是一个包含超过 4096 个字符的文本文件(我的机器的限制)。
然后我查看了this 常见问题解答,下面是我的新版本执行:
sub good_execute {
my($cmd) = @_;
print "[COMMAND]: $cmd\n";
my $in = gensym();
#---------------------------------------------------
# using $in, $out doesn't work. it expects a glob?
local *OUT = IO::File->new_tmpfile;
local *ERR = IO::File->new_tmpfile;
my $pid = open3($in, ">&OUT", ">&ERR", $cmd);
print "[PID]: $pid\n";
waitpid($pid, 0);
seek $_, 0, 0 for \*OUT, \*ERR;
if(<ERR>) {
print "[ERROR] : $_" while(<ERR>);
die;
}
print "[OUTPUT]: $_" while (<OUT>);
}
sort 命令现在可以正常执行,但我不知道为什么。
[更新]阅读@tchrist的回答后,我阅读了IO::Select,又在谷歌上搜索了一下,得出了这个版本的execute:
sub good_execute {
my($cmd) = @_;
print "[COMMAND]: $cmd\n";
my $pid = open3(my $in, my $out, my $err = gensym(), $cmd);
print "[PID]: $pid\n";
my $sel = new IO::Select;
$sel->add($out, $err);
while(my @fhs = $sel->can_read) {
foreach my $fh (@fhs) {
my $line = <$fh>;
unless(defined $line) {
$sel->remove($fh);
next;
}
if($fh == $out) {
print "[OUTPUT]: $line";
}elsif($fh == $err) {
print "[ERROR] : $line";
}else{
die "[ERROR]: This should never execute!";
}
}
}
waitpid($pid, 0);
}
这工作正常,现在有些事情变得更清楚了。但整体画面还是有点朦胧。
所以我的问题是:
-
hung_execute有什么问题? - 我猜
good_execute工作是因为 open3 调用中的>&。但是为什么以及如何? - 另外,当我使用词法变量(
my $out而不是OUT)作为文件句柄时,good_execute不起作用。它给出了这个错误:open3: open(GLOB(0x610920), >&main::OUT) failed: Invalid argument。为什么会这样? - 似乎只有一个文件句柄可以在给定时间写入,如果我丢弃持有资源的句柄,其他句柄会继续等待。我以前认为STDERR和STDOUT是独立的流,不共享任何资源。我想我的理解在这里有点缺陷。也请给我一些指示。
【问题讨论】: