Perl Parallel::ForkManager wait_all_children() 的执行时间过长

3

我有一个使用Parallel::ForkManager的脚本。然而,即使所有子进程都已完成,wait_all_children()过程仍然需要非常长的时间。我知道的方式是通过打印一些时间戳(如下所示)。有人知道可能是什么原因吗?(我的机器上有16个CPU核心)。

my $pm = Parallel::ForkManager->new(16);
for my $i (1..16) {
    $pm->start($i) and next;

    ... do something within the child-process ...

    print (scalar localtime), " Process $i completed.\n";
    $pm->finish();
}
print (scalar localtime), " Waiting for some child process to finish.\n"; 
$pm->wait_all_children();
print (scalar localtime), " All processes finished.\n"; 

显然,我首先会收到“等待某个子进程完成”的消息,时间戳可能是 7:08:35。然后我会得到一系列“进程 i 已完成”的消息,最后一个消息的时间戳是 7:10:30。然而直到 7:16:33(!)我才收到“所有进程已完成”的消息。为什么在 7:10:307:16:33 之间会有 6 分钟的延迟呢?谢谢!


这是你正在运行的代码吗?有一个不太明显的语法错误。 - Sinan Ünür
1个回答

8
我尝试了这个:
#!/opt/perl/bin/perl

use strict; use warnings;

use Parallel::ForkManager;

my $pm = Parallel::ForkManager->new(16);

for my $i (1..16) {
    $pm->start($i) and next;
    sleep rand 20;
    printf "%s : Process %d completed\n", scalar localtime, $i;
    $pm->finish;
}

printf "%s: Waiting for some child to finish\n", scalar localtime;
$pm->wait_all_children;

printf "%s: All processes finished.\n", scalar localtime; 

我得到了以下内容:
[sinan@archardy Src]$ ./y.pl
2010年3月11日17:14:16:进程3已完成
2010年3月11日17:14:16:正在等待某些子进程完成
2010年3月11日17:14:18:进程8已完成
2010年3月11日17:14:18:进程14已完成
<省略>...</省略>
2010年3月11日17:14:34:进程12已完成
2010年3月11日17:14:34:所有进程均已完成。

我在Linux上安装了perl 5.10.1和版本为0.7.5Parallel::ForkManager

因此,我得出结论,您遇到的任何问题都是由于执行时发生的问题导致的。

# ... do something within the child-process ...

更新: 问题在于,你在调用 finish 前就打印了 Process finished message。请尝试以下版本:

#!/opt/perl/bin/perl

use strict; use warnings;

use Parallel::ForkManager;

my $pm = Parallel::ForkManager->new(16);
$pm->run_on_finish( sub {
    printf "%s : Process completed: @_\n", scalar localtime
});

for my $i (1..16) {
    $pm->start($i) and next;
    sleep rand 20;
    $pm->finish;
}

printf "%s: Waiting for some child to finish\n", scalar localtime;
$pm->wait_all_children;

printf "%s: All processes finished.\n", scalar localtime;

请查看Parallel::ForkManager文档中的回调函数,获取更多信息。如果延迟消失,则您观察到的症状是因为在进程完成之前您声称已完成分叉进程。


你说得对,Sinan。我忘了提到这种延迟并不是每次都会发生。只有当我的每个子进程需要很长时间和许多系统资源才能完成时才会发生。然而,困扰我的是,无论子进程中发生了什么,在打印出最后一个“Process i completed”之后,它都不再相关。但是,以下是我得到的实际输出: 08:02:43:等待一些子进程... 08:06:00:第1组完成。 ... 08:06:12:第16组完成。 08:07:03:全部完成。 我在想是否应该显式释放一些阻塞等待的内存/资源? - Zhang18
@Zhang18,请查看我的更新答案,使用了run_on_finish回调函数。 - Sinan Ünür
我明白了。所以,如果我通过run_on_finish()打印时间戳,我会得到你期望的结果(即由于wait_for_children而没有额外的等待时间)。然而,我的问题因此变成了为什么子进程即使在循环内达到了那个打印语句,fork仍然不认为它已经“完成”了呢?确保,在循环内部我没有对任务做任何花哨的处理。它只是一堆算术计算加上一些数据库查询和文件I/O。延迟似乎是由$pm->finish()方法引起的,该方法未能捕获子进程实际完成时间。 - Zhang18
1
@Zhang18 子进程在 $pm->finish 返回之前并没有结束。请务必阅读 http://perldoc.perl.org/functions/exit.html,特别是最后一段。 - Sinan Ünür

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接