2010-08-06 45 views
5

我有一個Perl腳本,它分叉了許多子進程。我想要有一些功能,如xargs --max-procs=4 --max-args=1make -j 4,其中Perl將保持運行的給定數量的進程,直到它失去工作。perl進程隊列

很容易說fork四個進程並等待它們全部完成,然後再fork另外四個進程,但是我希望同時運行四個或n個進程,只要一個完成。

在Perl中有一種簡單的方法來實現這樣的進程池嗎?

回答

11

Forks::Super可以處理這個要求。

呼叫至fork()可以阻塞,直到活性子進程的數量低於5,也可以通過額外的參數到fork呼叫和要執行的任務可以排隊:

fork { sub => sub { ... task to run in subprocess ... } } 

當一個子進程結束後,隊列中的另一項工作將啓動。

(我是本模塊的作者)。

+0

是什麼塊和隊列之間的區別? – srchulo 2012-11-08 22:35:58

+1

'block'會讓你的程序等待,直到某些子進程完成,以便下一個任務可以開始。 'queue'將把當前任務放入一個隊列中,讓程序繼續運行。當其他子進程完成時,隊列中的作業將異步啓動。 – mob 2012-11-08 22:40:32

+0

哦,好的。非常感謝! – srchulo 2012-11-08 23:44:25

6

退房Parallel::ForkManager - 它確實很多你的描述。您可以設置最大數量的進程,並且回調函數一旦完成(只要有工作要做)就可以啓動新的子進程。

2

雖然我幾乎總是使用CPAN模塊,或寫在夢幻般的AnyEvent模塊的東西,我認爲其重要的是瞭解這些東西的引擎蓋下是如何工作的。這裏有一個除perl之外沒有依賴關係的例子。同樣的方法也可以用C編寫而不會有太多的麻煩。

#!/usr/bin/env perl 

use strict; 

## run a function in a forked process 
sub background (&) { 
    my $code = shift; 

    my $pid = fork; 
    if ($pid) { 
    return $pid; 
    } elsif ($pid == 0) { 
    $code->(); 
    exit; 
    } else{ 
    die "cant fork: $!" 
    } 
} 

my @work = ('sleep 30') x 8; 
my %pids =(); 
for (1..4) { 
    my $w = shift @work; 
    my $pid = background { 
    exec $w; 
    }; 
    $pids{$pid} = $w; 
} 

while (my $pid = waitpid(-1,0)) { 
    if ($?) { 
    if ($? & 127) { 
     warn "child died with signal " . ($? & 127); 
    } else { 
     warn "chiled exited with value " . ($? >> 8); 
    } 

    ## redo work that died or got killed 
    my $npid = background { 
     exec $pids{$pid}; 
    }; 
    $pids{$npid} = delete $pids{$pid}; 
    } else { 
    delete $pids{$pid}; 

    ## send more work if there is any 
    if (my $w = shift @work) { 
     my $pid = background { 
     exec shift @work; 
     }; 
     $pids{$pid} = $w; 
    } 
    } 
}