2009年10月29日木曜日

memo::Perlによる複数並列処理プログラム

現在実行しているプログラムでは大体20分で1/70が終わっていた。

バグがなければ一日程で計算が終了するだろう。

従来のやり方だとこの規模の計算を終えるのに一週間ほど(それも途中でマナカナが止まらなければの話)かかっていたので、この差は歴然と言える。ってか速えなおい・・・




忘れないうちに並列処理のやり方だけメモっておくので、プログラムに困った人(とくに後々再び同じことしようとして忘れて焦ってるオレ)はぜひ活用していただきたい。




必要なモジュール。

・Parallel::ForkManager
http://search.cpan.org/~dlux/Parallel-ForkManager-0.7.5/ForkManager.pm

・IPC::Shareable (バグ修正済み ver)
http://rt.cpan.org/Public/Bug/Display.html?id=33489

・Data::Dump
http://search.cpan.org/~gaas/Data-Dump-1.15/lib/Data/Dump.pm

Parallel~は二個以上の子プロセスを生成する際必要である。fork()を駆使してそのようにしてもいいが、こちらを使った方がはるかに簡単。なお、使用する際は各プロセスが同じディレクトリを使わないようにしないと、同じコマンドを実行した際こんがらがることになるので注意。

また、IPC~は子プロセス間で変数を共有したいときに使う。これがないとあとでdumpしたときに空の変数しか出力できない。

Data~で子プロセス間の出力結果を統合する。



以下サンプルコード。

-------------------------------------------------------------

use strict;
use warnings;

use Data::Dump qw(dump);
use IPC::Shareable;
use Parallel::ForkManager;

my $handle = tie my @result, 'IPC::Shareable', undef, { destroy => 1 };  #共有する変数
@result = ();

my $pm = Parallel::ForkManager->new(10); #最大プロセス数

$pm->run_on_start(
sub { my ($pid,$ident)=@_;
print "** $ident started, pid: $pid\n";
}
);

for (my $i = 0; $i <= 100; $i++) {
$pm->start($i) and next;
$handle->shlock;
#子プロセスにやらせる処理をここに
push($result[$i], #結果);  #なんか処理したやつの出力
$handle->shunlock;
$pm->finish($i);
}

$pm->wait_all_children; #全てのプロセス終了まで待機
dump(@result);   #結果を統合

--------------------------------------------------------------


push($result[$i], #結果)とすることで出力されるものの順番を決めている。これがないと子プロセスの終わった順に結果が@resultに格納されるが、こうしておけば各プロセスの結果にはfor文の「何番目か」という情報があるので、forの順番に@resultに格納されていく。


他、詳しくはこことか参照
http://perldoc.jp/docs/modules/Parallel-ForkManager-0.7.5/ForkManager.pod






とりあえず今日はここまで、これ以上やるとニューロンがプッツンしちゃいそうなのでやめておく。
また明日からがんばろう。

0 件のコメント: