2016-05-29 49 views
-1

我有一個複雜的perl代碼,這可能不實際。 我有一個包含數千個文件的文件夾,其中包含每個鏈接在網站上的點擊次數。使用數組推送使用站點過載使站點超載。 首先我使用glob函數來獲取數組中的所有文件。然後我使用foreach函數瀏覽文件夾內的所有文件。之後,我使用push功能將所有指定的數字和hrefs輸入到相應的鏈接。之後,按照數組排序,然後分頁。 有更好的解決方案嗎?比glob數組和數組更容易嗎?有沒有辦法只獲得20個文件數最高的數組? 此代碼使用了太多的處理請求。它使網站變得緩慢。 任何幫助,將不勝感激。謝謝。 下面是代碼:需要更好解決方案的不切實際的perl代碼

####################################### TOP LINKS 
elsif($rank eq "top_links" && $page ne "" && $start ne "" && $end ne ""){ 

    &open_div("$name_top_links_b - from $start to $end - Page $page"); 
    sub top_links_pagination($_[0],$_[1]){ 
     @topharray = glob("hits/*"); 
     foreach $hitsnumber(@topharray){ 
      open(TLH,"<$hitsnumber"); 
      $hitsnumberfh = <TLH>; 
      close(TLH); 
      $hitsnumber =~ s/hits\///i; 
      push(@array_reduce,$hitsnumberfh." <a href=\"http://".$address_without_http."/search.cgi?text_submit=".$hitsnumber."&amp;submit=Search&amp;search_type=match_case&amp;page=1&amp;start=0&amp;end=19\">".$hitsnumber."</a><br>\n\r"); 
     } 
     @array_main = sort{$b <=> $a}@array_reduce; 
     print @array_main[$_[0]..$_[1]]; 
     print "<br><br>"; 
    } 

    &top_links_pagination($start,$end); 
    $var_pre = scalar(@array_main); 
    $var_t = $var_pre /= 20; 
    $var_n = int($var_t) + 1; 
    for($x=0;$x<$var_n;$x++){ 
     print "<a class=\"touch\" href=\"".$website_url."/parameters.cgi?rank=top_links&amp;page=".($x+1)."&amp;start=".($x*20)."&amp;end=".($x*20+19)."\">".($x+1)."</a> "; 
    } 
    print "<br><br>&bull; <a href=\"http://".$address_without_http."/parameters.cgi?rank=last_links&amp;page=1&amp;start=0&amp;end=19\">See last links</a>"; 
    &close_div; 

} 
####################################### TOP LINKS 
+0

請正確縮進您的代碼。這很難讀取,因爲它8秒 – Borodin

+1

如果你每秒發出很多頁面請求,導致你的服務器變慢,你可以考慮創建一個單獨的進程來讀取'hits/*'並生成一個包含鏈接排名的文件(每1,5,10秒,或其他適當的)。然後,您可以在上面的腳本中讀取結果文件以提取相應的行。對於前N個鏈接,還可以考慮使用內存緩存,如memcached。 – xxfelixxx

回答

0

看起來你應該使用一個數據庫:-)

的文件夾上工作與成千上萬的文件是緩慢的。

沒有其他任何更改:期運用opendirreaddir可能提高速度一點點:

opendir my $hits_dh, 'hits'; 
while (my $fn = readdir($hits_dh)) { 
    next unless $fn =~ /^\./; # Skip ".", ".." and hidden files 
    open my $hits_fh, '<', "hits/$fn"; 
    ... # same processing as in your source 
} 
closedir $hits_dh; 

沒有閱讀完所有的文件名,他們每個人的工作可能會有點更快,更少的內存消耗之前。

使用數據庫是那麼容易,因爲

for my $hit_row ($dbh->selectall_arrayref(
    'SELECT hitsnumber, hits FROM hits_table ORDER BY hits DESC LIMIT 20' 
)) { 
    push @array_reduce, $hit_row->[1].' hits for '.$hit_row->[0]; 
} 

更換內容由您<a href="..."推到陣列。

假設你不能使用一個數據庫,內存緩存(如意見提出)或cron腳本(在後臺定期創建數據)由於某種原因:

my $hits_cache_fn = "/tmp/hits_cache.txt"; 

if (-e $hits_cache_fn) { 
    # Read the cache file 
    open my $hits_cache_fh, '<', $hits_cache_fn; 
    my %hits; 
    while (<$hits_cache_fh) { 
     chomp; 
     my ($hits_number, $hits) = split(/\:/); 

    } 
    close $hits_cache_fh; 
} else { 
    # Cache file doesn't exist - should only happen on first request 
    print "No hits information available."; 
} 

# Check modification time of cache file and update if older than 90 secs. 
my @cache_info = stats($hits_cache_fn); 
system "./update_cache.sh &" 
    if $cache_info[9] < (time - 90); 

update_cache.sh可能是:

#!/bin/bash 
cd hits 
grep -r '' . >/tmp/hits_cache.new 
mv /tmp/hits_cache.new /tmp/hits_cache.txt 

此文件將創建一個新文件,其中包含所有命中文件的文件名和內容。這個過程需要一些時間(大約比你當前的Perl腳本少一點),腳本運行時進入的任何請求都不應該使用部分緩存文件。這就是爲什麼使用臨時名稱創建緩存文件,然後重命名爲最終緩存文件名(這是一個原子操作:只更改文件名,不會複製內容)。

該解決方案將提供長達90秒的信息。你應該真的考慮這種類型的緩存,因爲大多數應用程序並不需要實時信息。

Unix的sort命令也應該能夠對列表進行排序和headtail可用於將其降低到前20行,但我沒有那麼多爲sort,使之排序的第二列。

0

真的非常感謝您的幫助。我很感激。我正在考慮使用數據庫,但維護它更復雜。使用mysql數據庫非常簡單。例如使用SORT和SELECT命令。但使其更加複雜。 我相信這個PUSH命令進入數組需要很多時間。至少有40%的時間加載此代碼。 但我沒有看到任何其他方式將它放入我以後需要的數組中。 我所做的就是縮短鏈接到@array_reduce的href鏈接,這樣我只打印不帶hrefs和描述的數字和名稱。但這只是一個臨時解決方案。如果我可以使用更快的push命令方式,也許另一種方法來替換$ hitsnumber =〜s/hits /// i;這是在foreach。