2010-03-24 17 views
6

Ich stelle etwas auf SSH auf mehreren Servern in "Chargen" aus. Ich möchte grundsätzlich 5 Verbindungen auf einmal aufrechterhalten, und wenn man fertig ist, öffne ein anderes (nach einem Array von Server-IPs).Wie kann ich einen Fork-Pool in Perl verwalten?

Ich frage mich für etwas wie das sollte ich fork() verwenden? Wenn ja, welche Logik kann ich verwenden, um sicherzustellen, dass ich 5 Kinder gleichzeitig behalte?

+0

See http://stackoverflow.com/questions/2453432/in-perl-how-can-i-wait-for-threads-to-end-in-parallel/2454146#2454146 –

Antwort

11

Forking (oder Threading) ist was Sie wollen, aber Sie sollten sich CPAN für Module ansehen, die das meiste von dem bieten, was Sie brauchen, um das Rad nicht neu zu erfinden und die Lernschwierigkeiten zu überwinden.

Zum Beispiel, Parallel::ForkManager sieht aus wie es genau ist, was Sie wollen.

use Parallel::ForkManager; 

$pm = new Parallel::ForkManager($MAX_PROCESSES); 

foreach $data (@all_data) { 
    # Forks and returns the pid for the child: 
    my $pid = $pm->start and next; 

    ... do some work with $data in the child process ... 

    $pm->finish; # Terminates the child process 
} 
+0

aber ForkManager doesn scheint wirklich einen Pool zu unterstützen, aber nur eine Obergrenze in der gleichzeitigen Anzahl von Prozessen? Start scheint dokumentiert zu sein, um immer eine neue Verzweigung für jede Iteration zu machen. Gibt es eine Bibliothek, die echtes Pooling von Fork-Prozessen unterstützt, sodass sie nicht für jede Iteration gespalten werden müssen? – TheArchitect

+0

Das mag stimmen. Was ich heute generell verwende, ist Thread :: Pool :: Simple. Es verarbeitet automatisch eine Min-/Max-Anzahl von Threads, die Sie definieren können, und verwaltet, wie viele basierend auf der Arbeitslast aktiv sind, und ermöglicht Pre/Post-Aktionen für jeden Job. Ich habe es jetzt schon einige Jahre lang gut genutzt. Es erfordert Threads, was für diejenigen unglücklich ist, die ein Perl verwenden, das ohne iThreads kompiliert wurde. AnyEvent :: Fork :: Pool sieht aus wie eine gute Wahl, wenn das der Fall ist, aber ich habe keine Erfahrung damit. – kbenson

4

Es gibt mehrere Module, die genau dieses Problem lösen. Siehe beispielsweise Parallel::ForkManager, Forks::Super oder Proc::Queue. (!)

+1

Proc :: Queue rockt für bestehende Skripte, da die eigentliche Forking-Aktion nicht geändert werden muss. Großer Vorschlag. Vielen Dank. –

0

Mein persönlicher Forking Favorit ist Proc::Fork

Allgemeine Übersicht von pod:

use Proc::Fork; 

run_fork { 
    child { 
     # child code goes here. 
    } 
    parent { 
     my $child_pid = shift; 
     # parent code goes here. 
     waitpid $child_pid, 0; 
    } 
    retry { 
     my $attempts = shift; 
     # what to do if if fork() fails: 
     # return true to try again, false to abort 
     return if $attempts > 5; 
     sleep 1, return 1; 
    } 
    error { 
     # Error-handling code goes here 
     # (fork() failed and the retry block returned false) 
    } 
}; 


Und die Anzahl der maximalen Prozesse für so etwas wie SSH Chargen laufen zu begrenzen dann soll dies das tun Trick:

use strict; 
use warnings; 
use 5.010; 
use POSIX qw(:sys_wait_h); 
use Proc::Fork; 

my $max = 5; 
my %pids; 

my @ssh_files = (
    sub { system "scp file0001 [email protected]:/somedir/." }, 
    ... 
    sub { system "scp file9999 [email protected]:/somedir/." }, 

); 

while (my $proc = shift @ssh_files) { 

    # max limit reached 
    while ($max == keys %pids) { 
     # loop thru pid list until a child is released 
     for my $pid (keys %procs) { 
      if (my $kid = waitpid($pid, WNOHANG)) { 
       delete $pids{ $kid }; 
       last; 
      } 
     } 
    } 

    run_fork { 
     parent { 
      my $child = shift; 
      $pids{ $child } = 1; 
     } 
     child { 
      $proc->(); 
      exit; 
     } 
    } 
} 

/I3az/

auch
+0

Proc :: Fork drosselt die Anzahl der Hintergrundprozesse? Wie beantwortet das das OP? – mob

+0

@mobrule: Sorry wurde weggerufen! Es gibt nichts Spezifisches (das ich kenne!) In Proc: Fork für Throttling. Kehren Sie also zu den normalen waitpid-Maßnahmen zurück (siehe mein aktuelles Beispiel). – draegtun

1
use Net::OpenSSH::Parallel; 

my $pssh = Net::OpenSSH::Parallel->new(connections => 5); 

for my $ip (@ips) { 
    $pssh->add_host($ip); 
} 

$pssh->push('*', command => 'do this'); 
$pssh->push('*', command => 'do that'); 
$pssh->push('*', scp_get => 'foo', 'bar-%HOST%'); 
$pssh->push('*', scp_put => 'doz', 'there'); 

$pssh->run; 
Verwandte Themen