Perl Parallel :: ForkManager,需要很长时间才能更改fork条件

时间:2015-04-20 06:02:47

标签: perl dictionary fork

在修改pid条件时,我有两个问题:Parallel :: ForkManager。

问题1:举一个简单的例子,

use strict;
use warnings;
use Parallel::ForkManager;
use IO::Socket ;

my $np = 32 ;
my $pm = Parallel::ForkManager->new($np);
$| = 1 ;

sub do_something{ #an example for 3 second delay
    my $port = shift @_ ;
    my $tgt = 192.168.0.1 ;
    my $sock = IO::Socket::INET->new(PeerAddr=>"$tgt:$port",Proto='tcp',Timeout=>3) ;
    $sock ? return $sock : return 0 ;
}

foreach (1..64) {
    $pm->start and next ;
    do_something($_) ;
    $pm->finish ;
}
$pm->wait_all_children ;

以上脚本可以使用

time perl simple_script.pl 

real    0m7.109s
user    0m0.237s
sys     0m0.080s

修改

$pm->start and next ; 
do_something($_) ;

$pm->start and next or do_something($_) ;

!($pm->start) or do_something($_) ; 

似乎也有效,但不是预期的。

time perl modified_script.pl 

real     3m12.307s
user     0m0.237s
sys      0m0.080s

似乎另外两个修改版本一次运行一个进程。

问题2:

有没有其他方法可以在不使用foreach循环中的下一个内容的情况下执行相同的操作?这样,脚本可以适用于map而不是foreach循环。

P.S:分叉和对象创建不是我的优点。

编辑:删除&根据建议。

2 个答案:

答案 0 :(得分:0)

如果你改变这个循环

foreach (1..64) {
  $pm->start and next;
  do_something($_);
  $pm->finish;
}

到这个

foreach (1..64) {
  !($pm->start) or do_something($_);
}

然后你删除了终止每个孩子的$pm->finish电话。这意味着子进程将继续执行for循环,尝试启动自己的子进程,这将失败(因为子进程需要自己的Parallel::ForkManager对象 - 他们不能使用父进程)等等他们每次都会do_something循环。此外,由于孩子们在多次执行子程序时会被延迟,因此在所有64个孩子都开始运动需要更长的时间,因为你在任何时候都有32个孩子的限制。

你可以写

for ( 1 .. 64 ) {
  my $pid = $pm->start;
  if ( $pid == 0 ) {
    do_something($_);
    $pm->finish;
  }
}

$pm->wait_all_children;

但正如我在评论中所说的那样,如果这只是为了让您滥用map而不是使用for那么请不要这样做

答案 1 :(得分:0)

您声明的更改不会导致此过程花费更长时间。因此,我将专注于您的问题:如何将foreach循环转换为map循环。

for (LIST) BLOCK可以写为map BLOCK LIST。问题是你不能使用next因为循环的每次传递都会返回一些东西(如果只是空列表)。

my $pm = ...;
map {
   if (!$pm->start) {
      do_something($_);
      $pm->finish;
   }
   ()
} 1..64;
$pm->wait_all_children();

sub child {
   my ($job) = @_;
   ...
   exit();
}

{
   my $pm = ...;
   map { $pm->start or child($_) } 1..64;
   $pm->wait_all_children();
}

我不知道你为什么要那样做。它只会让代码更难阅读。