为什么Parallel :: ForkManager创建子流程很好,但不能并行处理它们

时间:2014-07-08 17:50:39

标签: perl ssh parallel-processing

我正在处理以下问题。

我们有一个程序可以自动将配置推送到多个路由器。执行此操作的Perl程序使用Parallel::ForkManager库来完成这些推送的并行化。

在该计划的早期,以下情况发生......

$p = new Parallel::ForkManager($multi); 

创建分支的主循环如下...

foreach my $node (@files) {
    # only if we're running in parallel
    if (ref($p)) {
         $p->start() and next;
    }

    # ship the file & path off to the main sub that does
    # all the heavy lifting
    do_push($node);

    # only if we're running in parallel
    if (ref($p)) {
        $p->finish();
    }
}
# only if we're running in parallel
if (ref($p)) {
    $p->wait_all_children();
}

这里的do_push($node)子例程太长了,但总之,它为节点建立了一个日志文件,然后通过ssh连接到路由器并推送配置。然后退出并完成日志记录。

从表面上看,一切似乎都在工作,进程分叉,结果如预期。

...然而

虽然创建了单独的进程,但路由器的连接和配置的推送并不是并行发生的。通过netstat -an可以很容易地验证ssh连接只是按顺序发生,而不是并行发生。只有在一个连接关闭后,下一个路由器才会连接。简而言之,我一次只能获得一个ssh连接。

有没有人知道为什么会这样,或者在哪里继续解决这个问题?

[edit]

根据评论,这里是对子程序中发生的事情的总结。出于空间和安全原因,我无法将其全部放在这里。

子程序的开始如下......

sub do_push {
    my($data) = @_;
    my($path,$router) = @$data;
    $|++;  # hopefully speed things up

    ($DEBUG or ($v > 2)) && print STDERR "PROCESSING: $router ($path)\n";

接下来的过程是......

  • 打开一个日志文件,写入。
  • 实例化与路由器建立连接的模块。
  • 连接路由器。
  • 推送命令,验证命令,如果成功则提交。
  • 一直记录到日志记录文件。

子程序结束如下......

    # finished with this router...

    # append our archive file
    my $ts = tv_interval($t0, [gettimeofday()]);
    (!$DEBUG && $archive) && print S "ROUTER: $router:$ts:$disposition\n";
    ($DEBUG or ($v > 2)) && print STDERR "ROUTER COMPLETE: $router -> $ts sec\n";

    # unlock and close our files
    (($DEBUG > 1) or ($v > 2)) && print STDERR "UNLOCK AND CLOSE: $archfile\n";
    (($DEBUG > 1) or ($v > 2)) && print STDERR "UNLOCK AND CLOSE: $summary\n";
    (!$DEBUG && $archive) && flock(F, LOCK_UN);
    (!$DEBUG && $archive) && flock(S, LOCK_UN);
    (!$DEBUG && $archive) && close(F);
    (!$DEBUG && $archive) && close(S);

    return;
}

如果在调试模式下运行,子例程中的第一个调试语句:"PROCESSING: $router ($path)\n"仅在前一个路由器完全完成子例程之后打印。肯定是多个进程分叉,我已经验证。只是那个"东西"阻止进程运行直到上一个进程完成。我正在努力寻找那些"的东西"是。

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

<强> [解决]

我讨厌回答我自己的问题,但是我确实找到了阻止的原因......

原来,问题是文件访问问题。在do_push()循环中,程序记录到两个文件。一个文件是记录文件本身的结果,这个文件对子进程是唯一的,没问题。然而,该计划也写了一个&#34;摘要&#34;文件。所有子流程都记录了该文件。

会发生的事情是第一个线程会打开文件,记录一些东西,连接到路由器并推出命令。一旦完成,它将关闭文件。当然其他线程会阻塞,等待访问&#34;摘要&#34;文件。

对于小型路由器推送,一切都发生得如此之快,以至于看起来这一切都是并行发生的。只有当我们不得不向每个路由器推出1000个线路时,才会发现这并不是并行进行的。