レスポンスにかかる時間が読めない処理を並列処理したくて,子プロセスとの通信方法を考えてみるテスト.要するに俺メモ.最近,異様に物覚えが悪いし.
ど〜でもよいことだけど,fork したときに共有されるファイルディスクリプタって,ロックも共有されているということを初めて知りました...
パイプ編
#!/usr/bin/perl
use strict;
use warnings;
my $MAX_ID = 100;
my $MAX_PROCESS = 20;
sub child_handler {
my ($fh, $id) = @_;
print STDERR "start $id\n";
sleep((rand 10) + 1); # dummy sleep
print $fh "[$id]\n";
close $fh;
print STDERR "end $id\n";
}
sub parent_handler {
my ($result_hash, $process_data) = @_;
my $fh = $process_data->{fh};
my $data = <$fh>;
chomp($data);
# close は外の delete で勝手にやるらしい.
# close $fh;
$result_hash->{$process_data->{id}} = $data;
}
my %fh_hash;
my %result_hash;
for my $id (1 .. $MAX_ID) {
my ($from_child, $to_parent);
pipe($from_child, $to_parent);
print STDERR ("pipe[$id]: ",
fileno($from_child), " <= ", fileno($to_parent),
"\n");
if (my $pid = fork) {
## parent
$fh_hash{$pid} = {id => $id, fh => $from_child};
}
else {
## child
child_handler $to_parent, $id;
exit;
}
# parent
# 空きが有ればとりあえず起動
next if (keys(%fh_hash) < $MAX_PROCESS);
# 終了した子プロセスのデータ処理
my $wait_pid = wait;
parent_handler \%result_hash, delete $fh_hash{$wait_pid};
}
# 残り子プロセスのデータ処理
while ((my $wait_pid = wait) != -1) {
parent_handler \%result_hash, delete $fh_hash{$wait_pid};
}
# 結果処理
for my $id (sort {$a<=>$b} keys %result_hash) {
print "result $id: $result_hash{$id}\n";
}
一時ファイル編
#!/usr/bin/perl
use strict;
use warnings;
use File::Temp;
my $MAX_ID = 100;
my $MAX_PROCESS = 20;
sub child_handler {
my ($fh, $id) = @_; # ( 一時ファイルハンドル)
print "start $id\n";
sleep((rand 10)+1); # dummy sleep
# 出力を排他制御するため,ファイル名で開き直す
my $cfh;
open $cfh, '>>', $fh->filename or die $!;
flock $cfh, 2 or die $!;
seek $cfh, 0, 1;
print STDERR "LOCK OK $id\n";
print $cfh "[$id]\n";
flock $cfh, 0;
print STDERR "UNLOCK OK $id\n";
print STDERR "end $id\n";
}
my $fh = new File::Temp(UNLINK => 0);
print STDERR "tmp file: ", $fh->filename, "\n";
my $active = 0;
for my $id (1 .. $MAX_ID) {
unless (fork) {
## child
child_handler $fh, $id;
exit;
}
$active++;
next if ($active < $MAX_PROCESS);
wait;
$active--;
}
1 while (wait != -1);
# ファイルハンドルをつかんでいるので消しても問題なし
unlink $fh->filename;
# 結果処理
print while (<$fh>);

コメントする