• Emacs と Perl を使って,XML-RPC 経由で Movable Type のエントリを編集するツールを配布しています.良かったら持っていってください.( 2004/10/24 update) mapae logo
  • Movable Type で footnote*1 を生成する plugin を配布しています.良かったら持っていってください.( 2004/03/04 update )
  • その他の配布物等

*1: 脚注.よ〜するに,こ〜ゆ〜やつです.

時間的コストがかかる処理の並列動作

| コメント(0) | トラックバック(0)

レスポンスにかかる時間が読めない処理を並列処理したくて,子プロセスとの通信方法を考えてみるテスト.要するに俺メモ.最近,異様に物覚えが悪いし.

ど〜でもよいことだけど,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>);

トラックバック(0)

トラックバックURL: http://d.nym.jp/mt/trackback/1931

コメントする

最近のコメント

アーカイブ

Author

nym <n...@nym.jp>
Powered by Movable Type 5.12