我在工作中继承了一些代码,我试图改进。我的Perl技能有点缺乏,所以会喜欢一些帮助!
本质上,此脚本是SNMP轮询由数千个节点组成的网络,以更新其本地接口索引缓存。我发现它遇到了一个问题,它耗尽了它的记忆而失败了。代码如下(严重减少,但我认为你会得到这个小说)
use strict;
use warnings;
use Parallel::Loops;
my %snmp_results;
my $maxProcs = 50;
my @exceptions;
my @devices;
my %snmp_results;
my $pl = Parallel::Loops->new($maxProcs);
$pl->share(\%snmp_results, \@exceptions );
load_devices();
get_snmp_interfaces();
sub get_snmp_interfaces {
$pl->foreach( \@devices, sub {
my ($name, $community, $snmp_ver) = @$_;
# Create the new ifindex cache, and return an array reference to the new entries
my $result = getSNMPIFFull($name, $community, $snmp_ver);
if (defined $result && $result ne "") {
my %cache = %{$result};
print "Got cache for $name\n";
# Build hash of all the links polled through SNMP
# [ifindex, ifdesc, ifalias, ifspeed, ip]
for my $link (keys %cache) {
$snmp_results{$name}{$cache{$link}[0]} = [$cache{$link}[0], $cache{$link}[1], $cache{$link}[2], $cache{$link}[3], $cache{$link}[4]];
}
}
else {
push(@exceptions, "Unable to poll $name - $community - $snmp_ver");
}
});
}
此特定虚拟机具有3.1GB的ram可分配值,并且在此脚本未运行时闲置约83MB。如果我将maxProcs降低到25,它会很好但是这个脚本已经花了很长时间,因为设备数量很多+延迟,所以宁愿保持高并行度!
我感觉$pl->share()
正在与每个分叉进程共享不断扩展的%snmp_results
,这绝对没有必要,因为它没有读取/修改其他条目:只是添加新的条目。我有更好的方法吗?
我对my %cache = %{$result};
也有点不确定。如果这只是创建一个指针作为哈希然后很酷,但如果它正在复制,那也有点浪费!
任何帮助将不胜感激!
答案 0 :(得分:0)
可以在CPAN here中找到该模块的文档。
有一部分谈论表演:
此外,如果每个循环子返回大量数据,则需要这样做 被传达回父进程,并再次传达给父进程 除非循环体做一些,否则超过并行性能增益 繁重的工作。
您可能正在内存中移动变量的完整副本,如果要轮询的MIB和机器数量足够大,则推到机器的限制。
由于您正在做的是I / O密集型任务而不是可以从并行CPU处理中受益的CPU任务,我会重新考虑启动这么多(50!)线程进行轮询的方法。
$maxProcs
的程序运行到1到5个进程,看看它的行为方式。对代码进行一些分析,附上Devel::NYTProf
以检查您消耗时间的位置,以及增加进程数量实际上是否会带来更好的性能。Parallel::Loops
重新考虑此任务。使用use threads
[1]和不同线程(use threads::shared
)之间共享的哈希值可以获得更好的性能。 道歉,如果这可能是一个评论。由于存在所有限制,因此难以从SO开始:(
如果您已经找到了解决方案,那么如果您能与我们分享您的发现,那就太棒了。我之前不知道Parallel::Loops
,我想我可以给它一些用途。