2011-05-23 41 views
9

我有以下簡單的代碼來測試針對碰撞在主鍵上,我創造Fatest方式:PHP in_array()可怕的表現。搜索數組值

$machine_ids = array(); 

for($i = 0; $i < 100000; $i++) { 
    //Generate machine id returns a 15 character alphanumeric string 
    $mid = Functions::generate_machine_id(); 

    if(in_array($mid, $machine_ids)) { 
     die("Collision!"); 
    } else { 
     $machine_ids[] = $mid; 
    } 
} 

die("Success!"); 

知道爲什麼這是採取了許多分鐘運行?無論如何加快它?

+5

你有異型的'in_array'是罪魁禍首,而不是'Functions :: generate_machine_id()'? – deceze 2011-05-23 07:03:53

+0

你有'函數:: generate_machine_id'方便的代碼嗎? – cHao 2011-05-23 07:05:03

回答

11
for($i = 0; $i < 100000; $i++) 
{ 
    //Generate machine id returns a 15 character alphanumeric string 
    $mid = Functions::generate_machine_id(); 
    if (isset($machine_ids[$mid])) 
    { 
    die("Collision!"); 
    } 
    $machine_ids[$mid] = true; 
} 
11

爲此,請使用$mid作爲鍵,並將虛擬值作爲值。具體來說,而不是

if(in_array($mid, $machine_ids)) { 
    die("Collision!"); 
} else { 
    $machine_ids[] = $mid; 
} 

使用

if(isset($machine_ids[$mid])) { 
    die("Collision!"); 
} else { 
    $machine_ids[$mid] = 1; 
} 

在最後你可以提取你本來想用array_keys($machine_ids)的陣列。

這應該快得多。如果它仍然很慢,那麼你的​​是緩慢的。

EDITED按照註釋添加isset

+2

打我吧。 :)儘管你應該使用'isset($ machine_ids [$ mid])''。 – deceze 2011-05-23 07:06:29

+0

同意deceze,如果值爲整數0,空字符串,NULL等,我相信'if($ machine_ids [$ mid])'將返回false(不是真正的衝突)。無論如何'isset()'是要走的路。但是,我只注意到OP說它將始終是一個15個字符alphanum。 – 2011-05-23 07:11:10

+0

@deceze:有什麼理由? 'isset'的性能命中低於隱式轉換爲布爾值的性能命中嗎?或者它是理論上的 - 因爲在PHP中'0'也是錯誤的,這會不同於'isset'? (在這種情況下,我們所有的都是空的和空的,所以它是安全的) – Amadan 2011-05-23 07:11:26

3

檢查數組成員資格是O(n)操作,因爲您必須將該值與數組中的每個元素進行比較。將大量東西添加到數組後,自然會變得更慢。

如果您需要進行大量的成員測試(如此處所示),則應該使用支持O(1)成員測試(例如哈希)的不同數據結構。

1

重構代碼,以便它使用一個關聯數組來保存本機ID和使用isset檢查

if(isset($machine_id[$mid])) die("Collision"); 

$machine_ids[$mid] = $mid; 

使用isset應該更快