我有一个子程序,我可以像 I 一样进行串行优化,大致类似
sub overlap {
my $hash_reference = shift; # pass the hash to the subroutine
my %h = %{ $hash_reference }; # refer to the hash as %h
my $standard = shift; # this is the key that will be compared against
my $compared = shift; # this is the key being compared
my $start_index = 0; # this will continually be increased
# to save computation time
# I want to parallelize here
foreach my $s ( 0 .. scalar @{ $h{$standard}{end} }-1 ) {
foreach my $c ( $start_index .. scalar @{ $h{$compared}{end} }-1 ) {
... # abbreviated for minimal working example
}
}
return ($standard_indices_met_in_compared, \@overlay);
}
这是一个缓慢的子程序。我在大约12-14分钟内运行了数千次,但是一次又一次地运行会浪费时间。
我经常使用Parallel::ForkManager
进行系统处理,但这在这里效果不佳。
Parallel::ForkManager
的实施看起来像
use Parallel::ForkManager qw();
my $manager = new Parallel::ForkManager(2);
foreach my $s ( 0 .. scalar @{ $h{$standard}{end} }-1 ) {
foreach my $c ( $start_index .. scalar @{ $h{$compared}{end} }-1 ) {
$manager->start and next;
... # abbreviated for minimal working example
}
$manager->finish;
}
$manager->wait_all_children; # necessary after all lists
我看过线程等,但是看不到如何在这里申请。
我查看了Perl multithreading and foreach和线程的Perl文档以及其他许多来源,但我不知道如何应用之前已经完成的工作。我看到的一切看起来都只适用于系统命令。
我想写一个共享数组和标量,没有系统命令。如果我遗漏了什么,请告诉我。
如何在子例程中并行化foreach
循环?
答案 0 :(得分:3)
您是否真的尝试仅使用最多两个进程进行并行化?如果是这样,这可能是感知缓慢的原因。
并行化总是会产生开销。如果并行化10个进程,则无法保证10倍的加速。
我建议您将最大数量的流程打开,以便更合理,然后再试一次。如果这没有帮助,可能是由于:
答案 1 :(得分:1)
在我们看到Parallel::ForkManager部分后,我想解决所显示内容的直接错误,已在ysth的评论中注明。
为了清晰起见,仅显示循环,并且有更多有意义的限制,您有
use Parallel::ForkManager;
my $manager = Parallel::ForkManager->new(8);
foreach my $s ( ... )
{
foreach my $c ( ... )
{
$manager->start and next; #
# code # WRONG
} # Module: Can't fork inside child
$manager->finish; #
}
$manager->wait_all_children;
让我们看看这是怎么回事。
孩子在内环中分叉。但它退出之外的,意味着它运行整个循环。因此,每个孩子也会与父母一起执行创建新孩子的行。这将是一个真正的混乱,有一连串的孩子,他们之间的工作分工错误。
但该模块不允许这样做,抛出错误。你的真实代码与展示的不同吗?
现在考虑
foreach my $s ( ... )
{
$manager->start and next; # child forked
foreach my $c ( ... )
{ # Whole inner loop
# code # run by one child
} # for one value of $s
$manager->finish; # child exits
}
fork发生在内部循环之外,子进程运行整个循环,当前值为$s
。父对象跳到外循环的下一次迭代并分叉另一个子进程,该子进程运行内部循环,接下来是$s
的值。每个子项运行整个内部循环以获得$s
的后续值。所以外循环的迭代是并行执行的。
这就是你想要的。所以改变你的代码来做这件事,看看它是怎么回事。
要重复所说的内容,并非所有代码都能同时并行运行。有些代码根本无法并行运行,有些代码可能会出现明显的性能下降。