我正在试图弄清楚如何正确地为我正在进行的项目的一部分实现ForkManager,但是遇到了FM似乎正在产生进程和做事情的情况,但需要永远。
但是,当我在调试代码中尝试FM时(通过将max processes设置为0),代码在合理的预期时间范围内完成。
以下是我遇到问题的代码......
<div class="form-group">
<label for="annualeave" class="col-sm-8">Annual Leave :</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="annualeave" name="annualeave" ng-model="annualeave" placeholder="Enter the details" required>
</div>
</div>
因此,如果我将use strict;
use warnings;
use Parallel::ForkManager;
sub read_table {
# takes a filename and reads in a CSV file.
# works fine and thus is omitted here
}
sub foo {
# originally an Inline::C subroutine
# for purpose of debugging replaced with randgen
return rand;
}
my $cpu_count = 0; my $epsilon = 1e-16;
my @tt = read_table('tt.csv');
my @tc = read_table('tc.csv');
my @nm = ($epsilon) x scalar @tc;
my @results;
my $pm = new Parallel::ForkManager($cpu_count);
$pm->run_on_finish(sub{
my $i = $_[1]; my $m = $_[5];
$results[$i] = $m;
});
foreach my $i (0..$#tt) {
$pm->start and next;
my @r;
if (scalar @{$tt[$i]} > 1) {
foreach my $j (0..$#tc) {
if (scalar @{$tc[$j]} > 1) {
push @r, foo(scalar @{$tt[$i]}, scalar @{$tc[$j]}, \@{$tt[$i]}, \@{$tc[$j]});
} else {
push @r, $epsilon;
}
}
} else {
@r = @nm;
}
$pm->finish($i, [@r]);
undef @r;
}
$pm->wait_all_children;
设置为0,则该过程完成没有问题,原始C代码在几分钟内完成($cpu_count
只有~2秒),但是当FM如果打开,它似乎会持续很长时间。当我输入像sub foo {return rand;}
这样的印刷语句来诊断问题时,它似乎确实在运行。
如果我拿出所有与FM相关的代码并尝试使用常规的双foreach循环,那么运行时是一样的。
提前致谢!
答案 0 :(得分:3)
这是因为从子节点发送到父节点的数据被写入磁盘(请参阅Parallel::ForkManager中的RETRIEVING DATASTRUCTURES):
数据结构 在给定的子进程中引用的是序列化的并通过它写出到文件中 耐储藏。随后将该文件读回内存和新的数据结构 属于父进程的创建。请考虑一下表现 它可能意味着惩罚,所以尽量保持返回的结构小。
在调试模式下,不会发生分叉,因此可以直接传递结构而无需保存和加载。
Thread::Queue可能会产生更好的效果。
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;
sub read_table {
map [ map rand, 1 .. 100 ], 1 .. 100;
}
sub foo {
[ @_ ]
}
my $cpu_count = 20; my $epsilon = 1e-16;
my @tt = read_table('tt.csv');
my @tc = read_table('tc.csv');
my @nm = ($epsilon) x scalar @tc;
my @results;
my ($q_in, $q_out) = map 'Thread::Queue'->new, 1, 2;
my @workers = map threads->create(sub{
while(defined(my $i = $q_in->dequeue)) {
warn $i;
my @r;
if (scalar @{$tt[$i]} > 1) {
for my $j (0 .. $#tc) {
if (scalar @{$tc[$j]} > 1) {
push @r, foo(scalar @{$tt[$i]}, scalar @{$tc[$j]}, \@{$tt[$i]}, \@{$tc[$j]});
} else {
push @r, $epsilon;
}
}
} else {
@r = @nm;
}
$q_out->enqueue([$i, @r]);
}
}), 1 .. $cpu_count;
$q_in->enqueue(0 .. $#tt);
$q_in->end;
for (0 .. $#tt) {
my $r = $q_out->dequeue;
my $i = shift @$r;
warn "$i: $r->[2][2][1]";
}
$_->join for @workers;
答案 1 :(得分:0)
这是因为你的工作人员做得太少,以至于创建流程的开销更大,将数据传回给父工具的工作量大于实际工作量。
建议:
@tt
的单个元素,而是指定一组元素。@{$tt[$i]}
为空时的案例。choroba的解决方案减少了开销,但保持了原始程序的低效率。通过实施我的建议,他们的解决方案可以更快。
顺便说一下,$pm->finish($i, [@r]);
最好写成$pm->finish($i, \@r);
。无需创建新阵列。