2009-09-14 87 views
2

我有一些代碼,在一部分會得到很多執行,我很奇怪哪種方式是更有效的實現。我會用一個for循環來模擬部分被很多執行:Perl中的字符串比較或哈希查找更快嗎?

選項A:

my %sections = (
    'somestring1' => 1, 
    'somestring2' => 1, 
    'somestring3' => 1, 
    'somestring4' => 1 
); 

for (0..10000) 
{ 
    # $element is chosen at random 
    $namespace = $element if $sections{$element}; 
} 

選項B:

for (0..10000) 
{ 
    # $element is chosen at random 
    $namespace = $element if ($element eq'somestring1' || 
          $element eq'somestring2' || 
          $element eq'somestring3' || 
          $element eq'somestring4'); 
} 

任何基準這樣或知道答案,因爲我不熟悉基準測試工具。

這段代碼在這種情況下可能沒有意義,但它實際上是我需要使用的。

+2

首先讓它運行,然後讓它快速。 –

回答

17

Benchmark模塊使用cmpthese功能

use strict; 
use warnings; 
use Benchmark qw'cmpthese'; 

my %sections = (
    somestring1 => 1, 
    somestring2 => 1, 
    somestring3 => 1, 
    somestring4 => 1 
); 

my @elements = map { 'somestring' . int(1 + rand(10)) } 1 .. 100; 

my $namespace; 

cmpthese(100000, { 
    hash_value => sub { 
     foreach my $element (@elements) { 
      $namespace = $element if $sections{$element}; 
     } 
    }, 
    hash_exists => sub { 
     foreach my $element (@elements) { 
      $namespace = $element if exists $sections{$element}; 
     } 
    }, 
    string_cmp => sub { 
     foreach my $element (@elements) { 
      $namespace = $element if (
       $element eq'somestring1' || 
       $element eq'somestring2' || 
       $element eq'somestring3' || 
       $element eq'somestring4'); 
     } 
    }, 
}); 

我的結果(在WinXP運行的Perl 5.10):

   Rate string_cmp hash_value hash_exists 
string_cmp 18932/s   --  -44%  -50% 
hash_value 33512/s   77%   --  -12% 
hash_exists 38095/s  101%   14%   -- 

所以哈希查找比級聯的字符串比較快77%,檢查哈希存在而不是價值(如亞當貝萊爾建議)仍然快14%。

+0

我有一個不好的感覺,但我會有興趣看看如何測試正則表達式'/^somestring [1234] $ /'會比較這三種方法。我預計它不會像'存在'那麼快,但我想看看它如何與字符串比較疊加起來。 –

+0

我顯示'/^somestring [1234] $ /'比字符串比較慢了約3%,儘管真實世界的性能將在很大程度上取決於它們的值中的鍵的數量和模式(如果有的話)。 –

+1

<3邁克爾卡曼...給男人一條魚......教一個男人去釣魚...等 – mikegrb

4

散列查找機制相當快。

5

我的猜測是,第一個版本,exists會更快,更不用說更易讀和維護。

for (0..10000) 
{ 
    # $element is chosen at random 
    $namespace = $element if exists $sections{$element}; 
} 

僅僅檢查散列鍵的存在比檢索其用於比較值更快,所以使用exists

3

這可能是熟悉基準測試工具的時候了,比如CPAN模塊Benchmark

+0

這是真的,但是如果哈希變得非常大,我無法想象主張爲了性能原因將值內聯到巨大的布爾表達式中。 –

+0

你是對的,這意味着我誤解了這個問題..我認爲OP想要檢查密鑰是否在散列中所有密鑰的*子集*中,而不是散列本身。修復響應。 :) – Ether

0

Michael Carman的基準很好,但結果現在已經過時了,所以沒有在自己的機器上運行它的人可能會得到錯誤的想法。 因此,完全相同的基準測試中Mac Pro的瓦特/的Mac OS X和Perl 5.24.1上(只是10倍的情況下,給予更一致的結果):

   Rate string_cmp hash_exists hash_value 
string_cmp 54142/s   --  -28%  -32% 
hash_exists 74850/s   38%   --   -7% 
hash_value 80192/s   48%   7%   -- 

然而,在一個AWS在CentOS 7/Perl的5.24.0我們得到:

string_cmp 70373/s   --  -24%  -25% 
hash_value 92851/s   32%   --   -1% 
hash_exists 93545/s   33%   1%   -- 

所以,我要說測試自己的機器,但存在似乎並沒有提供一個好處目前(我的Mac上使用最新的Perl正是在這種特定的測試甚至可測量慢 - 甚至在其他測試中)。

我不喜歡關於基準的一件事是,它相當隨意地選擇比較4個平等與散列檢查。不要混淆,如果我們只有在散列一個項目,所以我們有一個平等的,我們得到(在我的Mac Pro/Perl的5.24.1)比較:

hash_value 119474/s   --   -1%  -14%  -34% 
hash_exists 121065/s   1%   --  -12%  -33% 
grep  138122/s   16%   14%   --  -23% 
string_cmp 180180/s   51%   49%   30%   -- 

我扔在那裏單grep,避免了foreach循環進行比較。因此,單一的平等,顯然比一個哈希檢查速度更快,但不是快兩倍,所以如果你可以用散列代替只有兩個等式檢查你得到的好處:

string_cmp 104167/s   --  -15%  -17% 
hash_value 121951/s   17%   --   -2% 
hash_exists 125000/s   20%   2%   -- 

然而,這與哈希前像在原始示例中那樣在循環外部構建。如果我們在每個基準週期上創建散列,該怎麼辦?即你有幾個值你想檢查數組中的存在,是創造一個哈希與他們值得的開銷?我不會給你帶來更多的結果,因爲你可能會發現它們在你的機器上是不同的,但答案是,對於2個值「取決於」(所以也許你不應該打擾),但是對於3個或更多,你應該做它。