加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

perl – 为什么IPC :: Open3陷入僵局?

发布时间:2020-12-15 22:02:14 所属栏目:大数据 来源:网络整理
导读:我浏览了 open3的文档,这里是我无法理解的部分: If you try to read from the child’s stdout writer and their stderr writer,you’ll have problems with blocking,which means you’ll want to use select() or the IO::Select,which means you’d best
我浏览了 open3的文档,这里是我无法理解的部分:

If you try to read from the child’s stdout writer and their stderr
writer,you’ll have problems with blocking,which means you’ll want to
use select() or the IO::Select,which means you’d best use sysread()
instead of readline() for normal stuff.

This is very dangerous,as you may block forever. It assumes it’s
going to talk to something like bc,both writing to it and reading
from it. This is presumably safe because you “know” that commands like
bc will read a line at a time and output a line at a time. Programs
like sort that read their entire input stream first,however,are
quite apt to cause deadlock.

所以我试过open3希望知道更好.这是第一次尝试:

sub hung_execute {
    my($cmd) = @_;
    print "[COMMAND]: $cmdn";
    my $pid = open3(my $in,my $out,my $err = gensym(),$cmd);
    print "[PID]: $pidn";
    waitpid($pid,0);
    if(<$err>) {
        print "[ERROR] : $_" while(<$err>);
        die;
    }
    print "[OUTPUT]: $_" while (<$out>);
}

有趣的是,我必须在这里初始化$err.

无论如何,这只是挂起,当我执行(“sort $some_file”);因为$some_file是包含4096个字符(我的机器的限制)的文本文件.

然后我查看了this FAQ,下面是我的新版本的执行:

sub good_execute {
    my($cmd) = @_;
    print "[COMMAND]: $cmdn";
    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",0);
    seek $_,0 for *OUT,*ERR;
    if(<ERR>) {
        print "[ERROR] : $_" while(<ERR>);
        die;
    }
    print "[OUTPUT]: $_" while (<OUT>);
}

排序命令现在执行正常,但是我不知道为什么.

[更新]阅读@ tchrist的答案后,我读了IO :: Select,经过一些更多的搜索,已经提出了这个版本的执行:

sub good_execute {
    my($cmd) = @_;
    print "[COMMAND]: $cmdn";
    my $pid = open3(my $in,$cmd);
    print "[PID]: $pidn";
    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调用.但为什么和如何呢?
>此外,当我使用词法变量(我的$out而不是OUT)来处理文件句柄时,good_execute没有工作.它给出了这个错误:open3:open(GLOB(0x610920),&& main :: OUT)failed:无效的参数.为什么这样?
>似乎只有一个文件句柄可以在给定的时间写入,如果我丢弃持有该资源的句柄,其他句柄将继续等待.我以前认为STDERR和STDOUT是独立的流,并没有共享任何资源.我想我的理解在这里有点有缺陷.请给我一些指针.

解决方法

你在文档中遇到了我写的很多问题,然后是一些.你是死锁的,因为你正在等待孩子退出,然后再读取它.如果它具有超过输出的管道缓冲区,它将阻塞并再次退出.此外,您还没有关闭手柄的两端.

你也有其他错误.你不能以这种方式测试句柄上的输出,因为你刚刚做了一个阻塞的readline并抛弃了它的结果.此外,如果您尝试在stdout之前读取所有stderr,并且如果在stdout上存在多个输出管道缓冲区,那么您的孩子会阻止写入stdout,同时阻止其从stderr读取.

你真的必须使用select,或者IO :: Select来做到这一点.只有当该句柄上有输出可用时,才能从句柄中读取,除非您非常幸运,否则您不得将缓冲的调用与select混合使用.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读