Hatena::ブログ(Diary)

Yet Another Hackadelic

2009-01-12

(Obsolete) Parallel::ForkManager + IPC::Shareable で複数のプロセスで変数を共有する

追記: 2011-12-20T03:18:11+09:00

結構この記事をしばしば参考にして安易にSystemV IPC 共有メモリに突っ込む事をやる人も居るようですが、IPC::Shareable 自体が長い事、メンテされてない上に、SystemV IPC 自体も古くさい手法です。大人しくファイルに書き出すなり、SQLite などを使って保存したりだとか、AnyEvent, Coro 等で書き直すとか、より簡単で確実な方法を試した方が良いでしょう。

つまるところ、この方法はお勧め出来ません。エントリ自体は削除せずに残しておきますが、そのつもりで読んで下さい。


オライリーの Perl クックブックの古い奴のレシピ 16.12 とかに書いてある内容なんですけど、自分でも試してみました。

IPC::Shareable のインストール

残念ながら現在のバージョン 0.60 はそのままだとテストが通りません。

に詳細があります。

次のパッチを当てます。

diff -cr IPC-Shareable-0.60.orig/t/38ipchv.t IPC-Shareable-0.60/t/38ipchv.t
*** IPC-Shareable-0.60.orig/t/38ipchv.t 2009-01-12 20:15:16.000000000 +0900
--- IPC-Shareable-0.60/t/38ipchv.t      2009-01-12 20:19:02.000000000 +0900
***************
*** 70,76 ****
      });
      %hv = ();
      kill ALRM => $pid;
!
      for (qw(eenie meenie minie moe)) {
        $ipch->shlock();
        $hv{$_} = $$;
--- 70,77 ----
      });
      %hv = ();
      kill ALRM => $pid;
!     sleep 1;
!
      for (qw(eenie meenie minie moe)) {
        $ipch->shlock();
        $hv{$_} = $$;

IPC-Shareable-0.60.patch とかって名前にしておいて、

$ cd /path/to/dir
$ wget http://search.cpan.org/CPAN/authors/id/B/BS/BSUGARS/IPC-Shareable-0.60.tar.gz
$ tar xfz IPC-Shareable-0.60
$ cd IPC-Shareable-0.60
$ patch -p1 < ../IPC-Shareable-0.60.patch

としてからいつも通りにインストールします。

サンプル

下記は @data が共有できていないので、最後に dump しても空っぽです。

子プロセス各々にコピーされてしまう訳ですね。

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);
use Perl6::Say;

use Parallel::ForkManager;

my @data = ();

my $pm = Parallel::ForkManager->new(10);

for my $i (0..100) {
    my $pid;
    $pid = $pm->start && next;
    push(@data, rand($i));
    $pm->finish;
}

$pm->wait_all_children;

say dump(@data);

そこで IPC::Shareable を使うと。

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);
use Perl6::Say;

use IPC::Shareable;
use Parallel::ForkManager;

my $handle = tie my @data, 'IPC::Shareable', undef, { destroy => 1 };
@data = ();

my $pm = Parallel::ForkManager->new(10);

for my $i (0..100) {
    my $pid;
    $pid = $pm->start && next;
    $handle->shlock;
    push(@data, rand($i));
    $handle->shunlock;
    $pm->finish;
}

$pm->wait_all_children;

say dump(@data);

とすると @data は shared memory に Storable で保存されるのでプロセス間で共有出来るようになります。

@data は共有変数なんで shlock, shunlock は必要です。

ちなみに tie した後に改めて初期化しないと、上手く動かないです。何もしてないのに shared memory から取得するような感じで落ちてる模様。

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

トラックバック - http://d.hatena.ne.jp/ZIGOROu/20090112/1231756261