2016-03-02 42 views
1

我在工作中繼承了一些代碼,我試圖改進它。我的Perl技能有點缺乏,所以會喜歡一些幫助!爲什麼Parallel :: Loops程序耗盡我的內存?

本質上,該腳本是SNMP輪詢數千個節點的網絡以更新其本地接口索引緩存。我發現它正在耗盡內存和失敗的問題。代碼如下(大量減少,但我想你會得到JIST)

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"); 
     } 
    }); 
} 

這個特定的VM具有RAM alloctable的3.1GB和怠速關於83MB的使用時,該腳本沒有運行。如果我將maxProcs降到25,它會很好地完成,但由於設備數量和延遲太多,這個腳本可能會花費很長時間,所以寧願保持高並行性!

我有一種感覺,$pl->share()與每個分叉進程共享不斷擴大的%snmp_results,因爲它不讀取/修改其他條目,因此不需要修改其他條目:只需添加新條目即可。有沒有更好的方法可以做到這一點?

我也對my %cache = %{$result};略有不確定。如果這只是創建一個散列指針然後很酷,但如果它正在做一個副本,那也有點浪費!

任何幫助將不勝感激!

+1

您是否確定這是完整的代碼?它看起來像'@ devices'還沒有被聲明。該程序不應該編譯。關於'%cache':它是在'if'內聲明的。 Perl中'my'的_Lexical_變量總是存在於封閉的_scope_中,在這種情況下,它是'if'的'{}'塊。因此,在循環的每次迭代中,它都會創建一個全新的'$ result'和'%cache',一旦它們超出scope_,GC將照顧它們。但'%cache'確實沒有必要。你可以用'$ result - > {foo}'替換每個'$ cache {foo}'。儘管我不知道「分享」。 – simbabque

+0

是的,@devices正在宣佈,剛剛在這篇文章的瘦身。抱歉! – Lokicat

+0

我也很滿意替代方法。我之前的這個人一直在寫數據庫的結果,但由於他不得不打開,在每個分支中寫入和關閉數據庫,由於無法打開文件,往往會失敗。 – Lokicat

回答

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,我想我可以給它一些用處。

+0

感謝您的信息!爲了記錄,我的臨時解決方案是在內存上投入大量內存(這不是一個解決方案,但現在就可以使用)。額外的RAM允許我保持maxProcs爲高。 CPU使用率永遠不會很高,maxProcs的高數量與延遲問題一起工作良好。將看看線程和共享雖然:) – Lokicat