【问题标题】:When opening n pipes to child processes executing xargs from Perl, n-1 processes receive an empty line当打开 n 个管道到从 Perl 执行 xargs 的子进程时,n-1 个进程收到一个空行
【发布时间】:2015-01-06 21:20:02
【问题描述】:

...另一方面,如果我在打开下一个管道之前向管道写了一些东西,这不会发生。

下面的代码应该更清楚:

sub test_concurrent_pipes
{
    my $write_at_once = $_[0];
    my $pipe_handle;
    my @pipe_handle_list;
    my $i;
    foreach $i ( 1..3 )
    {
        open ( $pipe_handle, "| xargs echo" ) or die ( "Cannot open pipe.\n" );
        if ( $write_at_once == 1 )
        {
          print $pipe_handle "Hello\n";
        }
        push( @pipe_handle_list, $pipe_handle );
    }
    foreach $pipe_handle ( @pipe_handle_list )
    {
        print $pipe_handle "world\n";
    }
    foreach $pipe_handle ( @pipe_handle_list )
    {
        close ( $pipe_handle );
    }
}

print "Test 0: open all pipes before writing\n";
test_concurrent_pipes(0);

print "Test 1: write Hello before opening next pipe\n";
test_concurrent_pipes(1);

运行我得到的测试

./test_pipe_2_xargs.pl 
Test 0: open all pipes before writing


world world world
Test 1: write Hello before opening next pipe
Hello
Hello
Hello world world world

正如您在测试 0 中看到的,连续打开 3 个管道而中间没有任何输出会生成 2 个空行。 奇怪的是,如果我用cat - 替换xargs echo,则不会产生空行。 xargs 的行为似乎也与其手册页相矛盾,其中指出 Blank lines on the standard input are ignored.

我怎样才能避免那些空行?

在 cygwin/XP 上的 Perl 5.14.2 和在 HP-UX 11.00 上的 Perl 5.8.8 会发生这种情况。

我最后写下我真正想做的事情,因为它在这里无关紧要:

通过 Perl 脚本有效地清理所有 Clearcase 视图中可见的所有派生对象,该脚本为每个视图派生一个进程以在从 VOB (rmdo) 中删除文件之前删除文件 (xargs rm)。

【问题讨论】:

  • 很好地提供了一个完整的例子。

标签: perl pipe xargs


【解决方案1】:

使“创建循环”使用局部变量 (my $pipe_handle) 可以解决问题。

foreach $i ( 1..3 )
{
    open ( my $pipe_handle, "| xargs echo" ) or die ( "Cannot open pipe.\n" );
    ...
}

【讨论】:

  • 如果你在 3 句话或更少的时间内解释原因,我会投票给你 :-)
  • 将您的答案与@fjardon 关于open() 文档的注释结合起来,我的快速“grok”是my 的作用域等同于在$pipe_handle 被调用时未定义open .
  • my 范围内的任何内容都是当前代码块的本地内容。在 Q 中,它在 foreach 之外,所以它被重用了——因此下一个“打开”正在破坏它。
【解决方案2】:

显然open 覆盖了$pipe_handle 指向的FILEHANDLE,使得@pipe_hanlde_list 中的所有引用都指向最新的打开管道。

文档指出$pipe_handle在调用open()时应该是未定义的...

【讨论】:

    【解决方案3】:

    不要与上面的答案相矛盾,但我认为你的做法很奇怪。为什么你需要同时管道任何东西?

    我认为您实际上并没有获得任何并行性 - 您只是在异步馈送管道。尤其是像rm 这样的东西,你提到 - 你的限制因素几乎永远不会是进程和 CPU,而是磁盘 IO。

    在上面的示例中 - 您正在 xargs 中异步构建文件列表,但在文件描述符为 closeed 之前,它实际上不会对命令执行任何操作。如果您不打算进行文件系统 IO,我建议您使用线程或分叉,但取消链接文件并不能很好地并行化。

    【讨论】:

      【解决方案4】:

      感谢 Filip 给出正确的答案,感谢 fjardon 和 Sobrique 查明问题的根源。

      通过open 函数文档和一些测试后,我了解到它可以通过两种方式运行: - 句柄未定义,在这种情况下,它会创建一个新句柄 - 或者句柄参数是一个标量,它成为句柄的名称。 我发现打开文档中的示例特别有趣,其中 C 代码文件在遇到 #include 指令时递归打开并分配给编号的文件句柄(process 函数中的fh<nn>)。

      所以在我的情况下,每个open 俱乐部成员(并关闭)先前打开的句柄(第一次调用除外)。因此,该列表包含同一管道的三个句柄。 注意:因为我使用的是use strict,所以我预计 Perl 会抱怨使用符号引用(strict refs 在使用符号引用时会产生运行时错误)。

      @Sobrique:作为旁注,在更正实际脚本并进行一些基准测试之后,事实证明并行执行命令确实会产生影响。 为了进行基准测试,我将 700 个文件名通过管道传输到在 17 个视图中运行的 xargs cleartool ls,并在并行执行时(实时)将其完成速度提高了 37%。 这很可能与每个视图运行一个进程、Clearcase 缓存和与 IO 无关的 Clearcase 内部结构有关。 但是我不想在这里开始讨论性能,主要问题已经理解并解决了。 谢谢大家,我感谢每一个输入。

      【讨论】:

        猜你喜欢
        • 2021-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-02
        • 2014-09-11
        • 2012-12-16
        • 1970-01-01
        相关资源
        最近更新 更多