代码之家  ›  专栏  ›  技术社区  ›  David L.

perl:从一个后圆线程关闭open2句柄

  •  3
  • David L.  · 技术社区  · 6 年前

    我只是想知道如何正确使用 open2 功能。

    请参见下面的示例。它适用于小型 $max 但是如果我写的足够长 $hIn 因此,最终它将被阻塞,因为没有任何东西连续读取输出上的数据。

    use 5.26.0;
    use IPC::Open2;
    my $max = 100000;
    my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
    {
        my $cnt = 0;
        #When $max is big (e.g. 100000) so the code below will get blocked
        #when writing to $hIn
        while ($cnt<$max) {say $hIn $cnt++;}
        close($hIn) || say "can't close hIn";
    }
    while(<$hOut>) { print; }
    close($hOut) || say "can't close hOut";
    waitpid( $pid, 0 );
    

    我能想到的唯一解决方案是启动另一个线程,在后台进行写作。

    通过下面的代码,我可以写入 欣欣 尽可能多的数据,并在主线程中读取它们,但是 欣欣 好像没有关门。正因为如此, while(<$hOut>) 等待更多输出时将永远无法完成。

    use 5.26.0;
    use threads;
    use IPC::Open2;
    my $max = 100000;
    my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
    my $thr = threads->create(sub {
        my $cnt = 0;
        while ($cnt<$max) {say $hIn $cnt++;}
        #The close does not have any effect here (although no error is produced)
        close($hIn) || say "can't close hIn";
    });
    #This outputs all the data written to $hIn but never leaves the loop...
    while(<$hOut> ) { print; }
    close($hOut) || say "can't close hOut";
    $thr->join;
    waitpid( $pid, 0 );
    

    我的问题是:

    • 如果我使用线程的方法是可以的,那么如何从后台线程关闭文件句柄?
    • 如果不好(实际上 use threads 在Perl中是不鼓励的),那么有人能提供一个Open2的工作示例吗?它可以写和读大量数据,而不会因为等待读写器而被阻塞?

    编辑:根据您的建议,下面是使用ipc::run实现上述代码的方法:

    use 5.26.0;
    use IPC::Run qw/ run /;
    my $max = 1000000;
    run sub {
            my $cnt = 0;
            while ($cnt<$max) {say $cnt++;}
        },
        "|", "cat",
        "|", sub {
            while(<> ) {
                print;
            }
        }
        or die "run sub | cat | sub failed: $?";
    

    它运行无缺陷,代码可读性很好…我很高兴了解这个模块。谢谢大家!

    然而,我认为这个问题没有答案。如果无法使用 Open2 直接地说,为什么会存在这样的情况并使人们困惑?另外,无法关闭来自不同线程的文件句柄对我来说似乎是一个错误(当然,这是-关闭至少应该报告一个错误)。

    1 回复  |  直到 6 年前
        1
  •  4
  •   ikegami Gilles Quénot    6 年前
    1. 程序停止,因为它正在写入的管道已满。
    2. 管道到 cat 因为 停止从中读取。
    3. 停止,因为它正在写入的管道已满。
    4. 管道从 因为程序没有从中读取,所以已满。

    所以你们有两个程序在等待对方做些什么。这是僵局。

    低级解决方案是使用 select 监控管道两端。

    高级解决方案是 IPC::Run IPC::Run3 为你努力工作。

    use IPC::Run qw( run );
    
    my $cnt_max = 100000;
    my $cnt = 0;
    run [ "cat" ],
       '<', sub { $cnt < $cnt_max ? $cnt++ . "\n" : undef };