2010-03-24 32 views
6

'Toplu işlerde' bir çok sunucuyu SSH'ye ayarlıyorum. Temel olarak, bir seferde 5 bağlantıyı korumak istiyorum ve biri diğerini açtığımda (bir dizi sunucu IP'sinin ardından).Perl'deki çatal havuzunu nasıl yönetebilirim?

Böyle bir şey için merak ediyorum fork() kullanıyorum? Eğer öyleyse, bir seferde 5 çocuğu tuttuğumdan emin olmak için hangi mantığı kullanabilirim?

+0

Ayrıca bkz http://stackoverflow.com/questions/2453432/in-perl-how-can-i-wait-for-threads-to-end-in-parallel/2454146#2454146 ama ForkManager gelmez –

cevap

11

Önyükleme (veya iş parçacığı) istediğiniz şeydir, ancak CPAN'a baktığınızda, tekerleği yeniden icat etmenizi ve yapmanız gereken şeylerin öğrenme acılarından geçmenizi önlemek için ihtiyacınız olan şeylerin çoğunu sağlayacak modüller için bakmalısınız. Örneğin, Parallel::ForkManager, ne istediğinizi tam olarak görüyor gibi görünüyor.

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

Gerçekten bir havuzu destekliyor gibi görünüyor, ancak aynı anda süreçlerin sayısı bir kap? başlangıç ​​her zaman her yineleme için yeni bir çatal yapmak için belgelenmiş görünüyor. Çatal işlemlerinin gerçek havuzlamasını destekleyen bir kütüphane var mı, bu yüzden her bir iterasyon için çatallanmaya ihtiyaçları yok mu? – TheArchitect

+0

Bu doğru olabilir. Bu günleri genellikle kullandığım şey, Thread :: Pool :: Simple. Tanımlayabileceğiniz minimum/maksimum iş parçacıklarını otomatik olarak işler ve iş yüküne göre kaç tane aktif olduğunu yönetir ve her iş için ön/son işlem yapılmasına izin verir. Bunu birkaç yıl boyunca iyi etki için kullandım. İş parçacıkları olmadan derlenmiş bir Perl kullananlar için talihsiz olan iş parçacığı gerektirir. AnyEvent :: Çatal :: Havuz, bu durumda iyi bir seçim gibi görünüyor, ancak onunla hiçbir deneyimim yok. – kbenson

4

Tam olarak bu sorunu çözen birkaç modül vardır. Örneğin, Parallel::ForkManager, Forks::Super veya Proc::Queue. (!):

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) 
    } 
}; 


Ve SSH gruplar gibi bir şey için çalışan maksimum süreçlerin sayısını sınırlamak için o zaman bu yapmalıyım

+1

Proc :: Mevcut komut dosyaları için sıraya girer, çünkü gerçek önyükleme eylemlerinin değişmesi gerekmez. Büyük öneri. Teşekkürler. –

0

Benim kişisel çatallaşma favori kapsülünden Proc::Fork

Genel bakış niteliğindedir hüner:

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/

+0

Proc :: Çatal arka plan işlemlerinin sayısını kısar mı? Bu OP'ye nasıl cevap veriyor? – mob

+0

@mobrule: Üzgünüm aradı! Kısıtlama için çatal: Belirli bir şey (biliyorum ki!). Bu yüzden normal bekleme durumuna geri dönün (güncellenmiş örneğime bakın). – 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; 
İlgili konular