2012年01月11日

大体いつもスクラッチで書いてて忘れるのでメモ。

pipe を使う場合

pipe() とか socketpair() とか色々方法はあるけど、素直に IO::Pipe 使っとくと簡単便利。コアモジュールですし。

use strict;
use warnings;
use IO::Pipe;

my $pipes    = [];
my $children = [];
for my $i (1..10) {
    push @$pipes, my $pipe = IO::Pipe->new;
    my $pid = fork;
    if ($pid) {
        # parent
        $pipe->reader;
        push @$children, $pid;
        next;
    }
    # child
    die $! unless defined $pid;
    $pipe->writer;
    print {$pipe} "pid: $$, index: $i\n";
    exit;
}

for my $pid (@$children) {
    waitpid($pid, 0);
}

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

この書き方だと、すべての子プロセスの終了を待ってから初めて親プロセスで読み込みを始めているけど、use POSIX 'wait_h' して waitpid(-1, WNOHANG) すれば終わった奴から読み込めるはず。

ファイルに書く場合

pipe だと、送受信できるサイズに限界があるので、ファイルを使ったほうが巨大なデータを送る場合は安全。

use strict;
use warnings;
use File::Temp qw(tempdir);
use File::Slurp qw(write_file read_file);

my $tmpdir = tempdir CLEANUP => 1;

my $children = [];
for my $i (1..10) {
    my $pid = fork;
    if ($pid) {
        # parent
        push @$children, $pid;
        next;
    }
    # child
    die $! unless defined $pid;
    write_file "$tmpdir/$$", "pid: $$, index: $i\n";
    exit;
}

for my $pid (@$children) {
    waitpid($pid, 0);
    print read_file "$tmpdir/$pid";
}

pipe の時と基本的な書き方は変わらない。pid 毎にファイルを作っておいたほうが何かと便利かもってぐらい。

ちなみに pipe もファイルも単なるバイト列しか送受信できないので、データ構造を送りたい場合はなんかしらのシリアライザーを使う必要がある。JSON とか Data::MessagePack とかそのへん。

Parallel::ForkManager の場合

ちなみに、Parallel::ForkManager 0.7.6 からは、run_on_finish() で子プロセスからデータを受信できる。
実際には、子プロセスの finish() のタイミングで pid 毎にファイルに Storable::store() して、親プロセスでは Storable::retrieve() しているので、さっき書いたようなことと一緒。

use strict;
use warnings;
use Parallel::ForkManager 0.7.6;
use Data::Dumper;

my $pm = Parallel::ForkManager->new(3);
$pm->run_on_finish(sub {
    my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data) = @_;
    print Dumper $data;
});
for my $i (1..10) {
    $pm->start and next;
    $pm->finish(0, { pid => $$, index => $i });
}

$pm->wait_all_children;

まとめ

プロセス間通信ってめんどいですね。

ちなみに、ここに書いてあるプログラムはエラーハンドリングとかシグナルとか考慮してないし、いろいろとあれです。親プロセスから子プロセスに書きこむやつとか書いてないし。めんどいから DBD::SQLite っていうのもありですね。

あと、別に fork したいんじゃなくて並列処理をしたくてその結果を受け取りたいんだぜって場合は Coro::Channel とか使うとシンプルに書けるんじゃないかと思います。

xaicron at 22:44コメント(1)トラックバック(0)Perl  この記事をクリップ!  はてなブックマーク  はてなブックマーク数
編集

トラックバックURL

コメント一覧

1. Posted by xeil   2012年02月05日 19:45
WWW::YouTube:Downloadが動きません・・・・・・・・・・・・・・
直してもらえませんか?????????????

コメントする

名前:
URL:
  情報を記憶: 評価:  顔   星
  絵文字
 
 
プロフィール

Perlが少しだけ出来る気になってます。
JavaScriptはよくわかりません。
Rubyもちんぷんかんぷんです。
Pythonは難しいです。
ActionScript勘弁してください。
Javaあばばばばば。
低級言語できません。

github
はてなブックマーク数
はてなブックマーク数
閃乱カグラ
『閃乱カグラ -少女達の真影-』オフィシャルサイト
記事検索
ホットなもの
  • ライブドアブログ