Perl fork在递归子例程中

时间:2014-02-13 23:10:48

标签: perl recursion fork

我正在尝试编写一个递归脚本,使用forks解析大目录以获得更好的性能。举一个简单的例子,假设我想要运行不超过10个并发分支的DFS,比如

#!/usr/bin/perl
use warnings;
use strict;
use Parallel::ForkManager;

my $pm = Parallel::ForkManager->new(10);
&proc_dir("/some/large/directory");
$pm->wait_all_children;

sub proc_dir {
  my $path = shift;
  my(@child_dirlist);

  if(opendir(DIR, $path)) {
    my @d = grep { -d "$path/$_" } readdir(DIR);
    @child_dirlist =  map { "$path/$_" } @d;
    closedir(DIR);
  }

  foreach my $d (@child_dirlist) {
    my $pid = $pm->start and next; #This will fail within child processes
    &proc_dir($d);
    $pm->finish;
  }
}

但是Parallel::ForkManager要求如果你想从子进程中分出更多的进程,你就会初始化另一个ForkManager,这种情况在这种情况下会破坏使用一个进程的目的。我已经尝试了其他一些模块/方法来做到这一点,但是没有取得任何成功,将叉子的数量限制在一些#/阈值并让它们以递归的方式工作。想知道是否有人设法解决类似的问题或知道一个简单的解决方法。

编辑:请假设我已经测试了足够的CPU和I / O负载不是少数叉子的问题。

1 个答案:

答案 0 :(得分:3)

我认为你不会意识到这种方法所带来的好处。您将简单地分叉无限数量的进程,直到您压倒机器为止。您的目标不是使用单个PFM实例,而是加快处理速度。

为此,我建议您查看File :: Find模块。这是一个与查找相关的Perl实现,很可能是您正在寻找的内容。

如果我理解您的示例代码,您只需查找目录,因此运行find2perl将为File :: Find生成包装脚本:

find2perl /usr/share/emacs/ -type d

将创建以下脚本(稍微减少):

#!/usr/bin/perl

use File::Find ();

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, '/usr/share/emacs/');
exit;

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -d _
    && print("$name\n");
}

在您想要的()子程序中,您可以随心所欲。它显示比查找更快,当然如果你将逻辑应用于每个文件并在脚本中执行,而不是在子进程中执行它。

如果要在多个进程中中断处理,我建议使用Parallel :: ForkManager迭代顶级子目录。

顺便说一句,我不担心实例化多个PFM对象。这是你最不担心的事情。每个子进程递归实现10个子进程的风险更大。

还有一件事:如果您仍想继续使用递归PFM方法,您可以尝试在Benchmark工具中相互运行这两种实现。

相关问题