perlでParallel::ForkManagerを用いて並列処理

perlで並列処理

ダウンローダーやアップローダー等を実装する際、
並列処理が必要になることがある。

Perlはスレッド対応にはなっているものの、スレッド間共有などの必要がなければフォークを使用した方が無難。

何も使わずにフォークを使用するには、子プロセスの終了通知「シグナル」を受け取る制御が必要だが、
Parallel::ForkManagerを使用することで、この作業を回避することができる。

rei1)丸腰で書く場合=子プロセスの終了したシグナルを受け取る。

use strict;
use POSIX();

sub reap {
    while(($child = waitpid(-1,&POSIX::WNOHANG)) > 0){ #wait pidをroopするのは
        print "Parent: reaped $child\n";
    }
    $SIG{CHLD} = \&reap;
}
$SIG{CHLD} = \&reap;

for my $i(1..10){
    my $pid = frok();
    if(! defined $pid){
        die "fork() failed..:$!";
    }
    if(! $pid){
        #child process
        print "Child: $$\n";
        sleep rand(5);
        exit 0;
    }
}

rei2)Parallel::Forkmanageを用いてforkする処理

use strict;
use LWP::UserAgent;
use Parallel::ForkManager;

my @urls = wq(
    http://www0.example.com/
    http://www1.example.com/
    http://www2.example.com/
    http://www3.example.com/
);

#max 5 process fork
my $pm = Parallel::ForkManager->new(5);
foreach my $url(@urls){
    $pm->start and enxt;
    eval{
        my $uri = URI->new($url);
        my $ua = LWP::UserAgent->new();
        $ua->mirror($uri,$uri->host().'.html');
    };
    $pm->finish;
}

シグナル処理とは?

Perl5.7.3以前=>unsafed_signal = perl binallyがシグナルを受け取った瞬間にハンドラが呼び出しされる
perl5.7.3以降=>delay_signal = perl内 one step終了後にハンドラが呼び出し

#Perlで使用できるシグナル一覧

$perl -MConfig -e 'print $Config{sig_name}, "\n"'
ZERO HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM
TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF ...

#たとえば、Ctrl+Cのシグナルを受け取る

$SIG{INT} = sub {warn "got SIGINT!"; exit 1};