2009-06-09 12 views
3

最近、2つのプロセス間で通信したいときに、(パイプ| - )を使用して問題が発生しました。 基本的に、子プロセスは親によっていっぱいになったSTDINを速く処理できませんでした。これにより、親はSTDINが解放されてゆっくり実行されるまで待つことになりました。子に書き込むときに親がブロックされないようにするにはどうすればよいですか?

STDINはどの程度の大きさで変更可能ですか?はいの場合は、ベストプラクティスのサイズはどのくらいですか?ここで

は、私が何を意味するか示すために、いくつかのコードサンプルです:このサンプルprocess_packetより遅いanother_process_packet

if ($child_pid = open($child, "|-")) 
{ 
    $child->autoflush(1); 

    # PARENT process 
    while (1) 
    { 

      # Read packet from socket save in $packet 
      process_packet($packet); 

      # forward packet to child 
      print $child $packet; 
    } 
} 
else 
{ 
    die "Cannot fork: $!" unless defined $child_pid; 
    # CHILD process 
    my $line; 

    while($line = <STDIN>) 
    { 
     chomp $line; 
     another_process_packet($line); 
    } 
} 

。このようなコードを書く理由は、私は同じデータをソケットから取得し、実際に一度取得することです。

ありがとうございます。

+0

プロデューサとコンシューマスクリプトの短縮版を投稿できますか? –

+0

brain d foy、変更ありがとうございます。しかし、この多くの間違いを抱えることは恥ずかしいです... – Omid

答えて

6

もちろん、親プロセス内にバッファすることができます。子供のfdが書き込み可能な場合(書き込みがブロックされない場合)にのみ書き込みを行います。あなたはsyswrite、またはイベントループを使用するように右引数でこれを自分で行うことができます。

use AnyEvent; 
use AnyEvent::Handle; 

# make child, assume you write to it via $fh 

my $done = AnyEvent->condvar; 
my $h = AnyEvent::Handle->new(fh => $fh); 

while(you do stuff){ 
    my $data = ...; 
    $h->push_write($data); # this will never block 
} 

$h->on_drain(sub { $done->send }); 
$done->wait; # now you block, waiting for all writes to actually complete 

編集を:これはテストされていないことに使用されるが、私はそれをテストし、それが動作します。 (私は遅い子としてperl -ne "sleep 1; print $_"を使用しました)。可能であればwhileループ中に書き込みが行われますが、ループは決してブロックされません。最後に、すべての書き込みが完了するまでブロックします。 http://gist.github.com/126488

あなたはどのように子ブロックのブロックループ見ることができますが、それは非ブロックループをブロックしない方法:

私のテストスクリプトはgist.githubです。明らかなときは、そのように置く;)

(最後に、親指の一般的なルールとして、あなたがネットワークまたは他のプロセスと相互作用している場合、あなたはおそらくイベントループを使用する必要があります)

+0

ありがとうございます、しかし私は何らかの理由で親をブロックしたくありません。 おそらく私はAnyEventについてもっと読む必要があります。おかげさまで – Omid

+0

さて、ブロックしないでください。私はプロセスが終了しようとしているので、最後にブロックするだけです。あなたが未書き込みのデータで終了すると、子プロセスは決してそれを見ません。 これは長時間実行するプロセスであれば、ブロックする必要はありません。 – jrockway

+0

AnyEvent :: Handleはうまくいくようですが、まだ問題はあります。 STDINバッファをいっぱいにするために子プロセスを停止した後、親プロセスはデータをwbufにプッシュしますが、それはやりとりすることですが、私が子プロセスを解放した後、子プロセスはSTDINバッファ決してwbufに触れないでください。それから、wbufにデータをSTDINに強制的に送るために、$ done-> recvを使って親を待つためにon_drain(sub {$ done-> send})と行を使用しますが、ソケットから来ます。 どのように私はこの問題を処理することができますか? – Omid

0

プロセスhandleには、 'blocking'という名前のメンバ関数が含まれています。ブロッキングを0に設定するだけで、親プロセスはブロックされません。

if ($child_pid = open($child, "|-")) 
{ 
    $child->blocking(0); # Key to the solution. 
    $child->autoflush(1); 

    # PARENT process 
    while (1) 
    { 

      # Read packet from socket save in $packet 
      process_packet($packet); 

      # forward packet to child 
      print $child $packet; 
    } 
} 
else 
{ 
    die "Cannot fork: $!" unless defined $child_pid; 
    # CHILD process 
    my $line; 

    while($line = <STDIN>) 
    { 
     chomp $line; 
     another_process_packet($line); 
    } 
} 
+0

おかげでCheok :) – Omid

+0

子供は正しく動作しません。 – Omid

関連する問題