【发布时间】:2014-07-08 17:50:38
【问题描述】:
在处理一些遗留代码时,我是否被以下问题难住了。
我们有一个程序可以自动将配置推送到多个路由器。执行此操作的 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 连接。
有谁知道为什么会这样,或者从哪里着手解决这个问题?
[编辑]
基于cmets,这里总结一下子程序中发生的事情。出于空间和安全原因,我无法将其全部放在这里。
子程序的开始如下...
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" 仅在前一个路由器完全完成子例程后打印。肯定有有多个进程分叉,我已经验证了。只是“某事”阻止进程运行,直到前一个进程完成。我正在努力寻找那个“东西”是什么。
感谢任何帮助。
【问题讨论】:
-
你是说程序只有一个子进程被创建一次(如使用
ps所见)?如果是这样,$multi必须是1。如果不是,则与 P::FM 无关。 -
@ikegami 不,它正在生成多个分叉进程,而不仅仅是一个。
-
那么 P::FM 工作正常。如果您的代码中的其他地方存在问题,我们需要了解更多信息。
-
@ikegami 不幸的是,通过子例程调用的是 1000 行代码,以及多个模块、文件访问、解密库、通过 ssh 的 telnet 进程等。我需要一些时间尝试提炼正在发生的事情,主要是我正在寻找一个起点。我理解您的担忧。
-
要找出阻塞的原因,只需在 sub 中添加跟踪语句即可。 (在日志消息中包含
$$或记录到名称包含它的文件,以便您知道哪个进程正在记录什么。)
标签: perl ssh parallel-processing