多个叉子和IO:管道

时间:2015-03-03 11:31:21

标签: perl pipe

我正在尝试构建一个程序,它创建一些forks并将fork的结果写回主程序。因此我尝试使用IO::Pipe

sub ForkRequests {

  my $pipe = IO::Pipe->new();
  my $pid;

  foreach my $feature ( @features ) {

    if ( $pid = fork() ) {
      $pipe->reader();
      while ( <$pipe> ) {
        print $_. "\n";
      }
    }
    elsif ( defined $pid ) {

      #child
      $pipe->writer();

      #somecalculations [...]
      print $pipe $calcresults;
    }
  }
}

我从模块的文档中获取了管道的代码。

如果我现在尝试执行,我会收到一条错误消息

Can't locate object method "reader" via package "IO::Pipe::End" at lmtest3.pl line 56.
Can't locate object method "writer" via package "IO::Pipe::End" at lmtest3.pl line 63.
Can't locate object method "reader" via package "IO::Pipe::End" at lmtest3.pl line 56, <GEN0> line 1.
Can't locate object method "writer" via package "IO::Pipe::End" at lmtest3.pl line 63, <GEN0> line 1.

因此,我的代码似乎不会启动管道对象,而是IO::Pipe::End。 所以我的问题是,有人能看到那里的错误吗?为什么它会返回错误的对象,以及如何正确完成?

修改

我对某些服务器有一些请求(大多数时候1请求7个错误)。 这些请求名称保存在@features中,并将在#somecalculations处执行。

因为服务器响应很慢,我希望这些请求并行启动。他们都必须回到主程序并将回复打印到控制台。

我试过这段代码

sub ForkRequests {

  my $i = 0;
  my @pipes;
  my $pid;

  foreach my $feature ( @features ) {

    @pipes[$i] = IO::Pipe->new();
    if ( $pid = fork() ) {
      @pipes[$i]->reader();
    }
    elsif ( defined $pid ) {

      #child
      @pipes[$i]->writer();

      # calculations
      my $w = @pipes[$i];
      print $w $calc;
      print $w "end\n";
    }

    $i++;
  }
}

if ( $pid == 1 ) {
  while ( 1 ) {
    foreach my $pipe ( @pipes ) {
      while ( <$pipe> ) {
        unless ( $_ == "end" ) {
          print $_. "\n";
        }
        else { last; }
      }
    }
  }
}
else {
  exit;
}

}

如上所述,为了保存这些管道,但我仍然在阅读它们时遇到问题,因为程序会在得到答案之前退出。

1 个答案:

答案 0 :(得分:3)

问题在于您要求多个子进程,但尝试对所有子进程使用相同的管道。

reader方法将$pipe转换为可以从中读取数据的IO::Pipe::End对象,因此第一个子项正确连接。但是,然后再次在reader上调用$pipe,并抛出错误,因为它不再是正确类的对象。

您只需为每个子进程创建一个新管道:

sub fork_requests {

    for my $feature ( @features ) {

        my $pipe = IO::Pipe->new;
        my $pid;

        if ( $pid = fork ) {
            $pipe->reader;
            print while <$pipe>;
        }
        elsif ( defined $pid ) {
            $pipe->writer;
            # some calculations . . .
            print $pipe $calcresults;
            exit;
        }
    }

}

<强>更新

好吧,我想我明白你需要什么。这个完整的程序应该告诉你。

我已经编写了fork_requests,因此它需要一个功能列表作为参数,并且我编写了子代码,以便它休眠两秒钟来模拟处理时间,然后只需打印功能的名称

如我所建议的那样,父代码将所有管道存储在一个数组中,并按照它们排队的顺序打印每个管道的输出。所有五个子进程在两秒后完成,因此父进程暂停,然后打印最初传入的功能。

use strict;
use warnings;

use IO::Pipe;

STDOUT->autoflush;

fork_requests('A' .. 'E');

sub fork_requests {

    my @pipes;

    for my $feature ( @_ ) {

        my $pipe = IO::Pipe->new;
        my $pid;

        if ( $pid = fork ) {
            $pipe->reader;
            push @pipes, $pipe;
        }
        elsif ( defined $pid ) {
            $pipe->writer;
            select $pipe;
            # some calculations . . .
            sleep 2;
            my $calcresults = $feature;
            print $calcresults, "\n";
            exit;
        }
    }

    for my $pipe ( @pipes ) {
      print while <$pipe>;
    }

}

<强>输出

A
B
C
D
E