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

パイプにはサイズに制限があります。あなたのアプローチは行き詰まります

  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

考えられる解決策の 1 つ:

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には、これも簡単にするツールがあります。

Unixy の方法はIO::Selectを使用することですが、それは本当に面倒です。

于 2011-09-02T20:16:55.537 に答える
3

はい、プログラムの作成方法によっては、バッファー容量の制約に遭遇します。入力バッファ ( Reader) がいっぱいになり、外部プログラムの実行がブロックされます。

外部プログラムが入力バッファを埋めるのとほぼ同じ速度で入力バッファを空にするため、読み取りと書き込みを混在させると役立ちます。

もう1つ役立つのは、プロセス間通信にパイプやソケットの代わりにファイルを使用することです(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 に答える