您所问的问题看起来很简单,但实际上比看起来要复杂得多。
在 perl 中并行化并不难,但是……这里是龙。当您的程序变得不确定时,并行代码会引入一组全新的错误和竞争条件。您不再能够可靠地知道执行顺序。 (如果你假设你这样做了,你会创建一个竞争条件)。
但考虑到这一点 - 实际上有 3 种(ish?)方法可以解决。
分叉
使用Parallel::ForkManager 并将您的内部循环包含在一个叉子中。这非常适用于“简单”并行性,但在您的分叉之间进行通信很困难。
#!/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)通常更好。但是,您不应该将线程视为轻量级线程(如分叉),因为尽管您可能会从其他语言中想到 - 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 个 CPU 会加快您的速度。
...但是如果您的限制资源是 IO - 网络或磁盘带宽 - 它通常无济于事,因为争用实际上使问题变得更糟。尤其是磁盘控制器已经非常高效地进行并行化、预取和缓存,因此并行访问它们所获得的收益通常非常微不足道。