如何并行运行perl脚本

时间:2017-04-18 04:54:27

标签: perl parallel-processing

如何每次与不同的输入参数并行运行perl脚本:

插图:

perl example.pl param1 param2
perl example.pl param3 param4

我希望使用不同的输入example.pl运行perl脚本paramsX 2次或更多次。每次它应该并行运行。

示例算法如下:

my $params='1,2,3,4,5';   
my @all_params = split(/\;/, $params);
foreach my $entry (@all_param)
    {
      perl example.pl $entry
    }

我想为每个循环并行运行perl脚本。

2 个答案:

答案 0 :(得分:4)

没有必要编写任何代码(Perl或其他)来并行运行脚本,你可以只使用 GNU Parallel 并控制运行时间的数量,脚本有多少不同的服务器在结果和任何其他方面运行。

因此,如果您有一个名为params.txt的文件,其中包含:

param1 param2
param3 param4

你可以在终端中执行此操作:

parallel -a params.txt perl {1} {2}

如果您想要进度条,只需添加--bar

parallel --bar ...

如果你想一次只运行8个:

parallel -j 8 ...

如果你想在没有真正做任何事情的情况下看到它会做什么:

parallel --dry-run ...

答案 1 :(得分:2)

你问的东西看起来很简单,但实际上看起来比看起来要复杂得多。

在perl中并行化并不太难,但是......这里有龙。当您的程序变得不确定时,并行代码会引入一组全新的错误和竞争条件。您无法再可靠地了解执行顺序。 (如果你假设你做了,你将创造一个竞争条件)。

但考虑到这一点 - 实际上有三种方式可以解决它。

使用Parallel::ForkManager并将内循环包含在一个分叉中。这对于“简单”的并行性很有效,但是在你的forks之间进行通信很困难。

#!/usr/bin/env perl

use strict;
use warnings;

use Parallel::ForkManager;

my $manager = Parallel::ForkManager->new(2);    #2 concurrent

my $params = '1,2,3,4,5';
my @all_params = split( /,/, $params );

foreach my $entry (@all_param) {
   $manager->start and next;
   #your code to run in parallel here;
   print $entry;
   $manager->finish;
}

你可以使用fork滚动自己,但你可能会因为这样做而绊倒。所以Parallel::ForkManager是工作的工具。

主题:

#!/usr/bin/env perl

use strict;
use warnings;

use threads;
use Thread::Queue

  my $work_q = Thread::Queue->new;

sub worker {
   while ( my $item = $work_q->dequeue ) {
      print $item, "\n";
   }
}

my $params = '1,2,3,4,5';
my @all_params = split( /,/, $params );
$work_q->enqueue(@all_params);
$work_q->end;

threads->create( \&worker ) for 1 .. 2;    #2 in parallel
foreach my $thr ( threads->list ) {
   $thr->join;
}

如果你需要做更多的IPC,这更适合 - 线程(IMO)通常更好。但是,你不应该将线程视为轻量级(如forks),因为尽管你可能会想到其他语言 - 但perl线程并不像那样。

使用IO :: Select和多个open调用并行化:

#!/usr/bin/env perl

use strict;
use warnings;

use IO::Select; 

my $params = '1,2,3,4,5';
my @all_params = split( /,/, $params );

foreach my $param ( @all_params ) { 
   open ( my $io, '-|', "program_name $param" ); 
   $select -> add ( $io ); 
}

while ( my $fh = $select -> can_read ) { 
   my $line = <$fh>;
   print $line; 
}      

您可以通过IPC::Run2执行类似的操作来打开STDIN和STDERR的文件描述符。

我应该吗?

并行代码不是灵丹妙药。它的作用是减少'块'并让你消耗资源。如果您的限制资源是CPU,并且您有10个CPU,那么并行使用10将加快您的速度。

...但是如果您的限制资源是IO - 网络或磁盘带宽 - 它通常没有帮助,因为争用实际上会使问题变得更糟。特别是磁盘控制器已经非常有效地并行化,预取和缓存,因此并行获取它们的收益往往非常微不足道。