2

我的任务是使用外部实用程序(addr2line)从 perl 脚本中过滤一些数据。数据量相当大。我需要将大量数据打印到stdin程序并读回大量数据(从stdout程序到我的脚本)。

现在我用 做这个IPC::Open2,但我不混合阅读和写作。这合法吗?会Open2在管道中缓冲任何大小的数据吗?

我的代码:

my $cmd="addr2line -e $prog_name ";
use IPC::Open2;
local (*Reader, *Writer);
my $pid = open2(\*Reader, \*Writer, $cmd);
for(@requests) {  # this array is HUGE, 100s of thousands of entries
    print Writer "$_\n";
}
close Writer;  
for(@requests) {
    $function_name = <Reader>;
    $filesource = <Reader>;
   #... store ..
}
close Reader;
waitpid($pid,0);
4

2 回答 2

3

是的,您会遇到程序编写方式的缓冲区容量限制。您的输入缓冲区 ( Reader) 将填满并阻止外部程序的执行。

混合读取和写入会有所帮助,因为您清空输入缓冲区的速度与外部程序填充它的速度大致相同。

另一件有帮助的事情是使用文件进行进程间通信,而不是使用管道或套接字(就像IPC::Open2那样)。那么您将仅受可用磁盘空间量的限制。你可以自己做,但Forks::Super默认情况下使用 IPC 文件。

use Forks::Super 'open2';

...
my ($Reader,$Writer,$pid) = open2(@command);
for (@requests) { print $Writer "$_\n" }
close $Writer;
for (@requests) { ... read ... }
close $Reader;
waitpid $pid,0;
于 2011-09-02T16:06:50.977 回答
3

管道的尺寸有限。你的方法会陷入僵局

  Parent                 Child
  ------                 -----
  ...                    ...
                         Wait for data in Writer
  Put data in Writer
                         Read data from Writer
                         Put data in Reader
                         Wait for data in Writer
  Put data in Writer
                         Read data from Writer
                         Put data in Reader
                           => Blocks cause Reader is full
  Put data in Writer
  Put data in Writer
  ...
  Put data in Writer
  Put data in Writer
    => Blocks cause Writer is full

一种可能的解决方案:

use strict;
use warnings;
use threads;
use IPC::Open2 qw( open2 );

my @cmd = ("addr2line", "-e", $prog_name);

local (*Reader, *Writer);
my $pid = open2(\*Reader, \*Writer, @cmd);

my $thread = async {
   for (;;) {
       $function_name = <Reader>;
       last if !defined($function_name);
       $filesource = <Reader>;
       #... store ..
   }

   close Reader;
};

{
   my @requests = ...;

   for(@requests) {  # this array is HUGE, 100s of thousands of entries
      print Writer "$_\n";
   }

   close Writer;
}

$thread->join();
waitpid($pid, 0);

或者,IPC::Run也有工具可以让这变得简单。

统一的方法是使用IO::Select,但这真的很痛苦。

于 2011-09-02T20:16:55.537 回答