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 とか使うとシンプルに書けるんじゃないかと思います。
トラックバックURL
コメント一覧
直してもらえませんか?????????????

