2010-05-01 66 views
9

我目前使用md5_file()來運行約15個URL並驗證它們的MD5散列值。有什麼方法可以讓這個更快?貫穿它們需要很長的時間。使md5_file()更快的方法?

+0

「遍歷約15個URL」是指類似'md5_file('http://some.url/foo')'在一個循環中與15個不同的URL?這些「文件」有多大? – VolkerK 2010-05-01 14:17:03

+0

是的,就是這樣。我將它們從MySQL數據庫中提取出來,然後在循環中運行它們到md5_file($ result)中。這些文件非常小,實際上沒有顯示輸出,沒有用戶界面,查看時只是一個空白的白頁 – Rob 2010-05-01 14:19:25

+0

問題是,你是按順序計算哈希值而不是平行計算哈希值, 'md5_file'不是瓶頸。另外,一個空文件的哈希值肯定是一樣的。 – salathe 2010-05-01 14:38:12

回答

15

也許你現在正在按順序進行。即獲取數據1,處理數據1,獲取數據2,處理數據2 ...,瓶頸可能是數據傳輸。
你可以使用curl_multi_exec()來平行一點。 要麼註冊CURLOPT_WRITEFUNCTION並處理每個數據塊(由於md5()只處理一個數據塊,所以很棘手)。
或檢查已完成的捲曲手柄,然後處理該手柄的數據。

編輯:使用hash extension(其中增量散列函數提供)和php5.3+ closure快速&骯髒的例子:

$urls = array(
    'http://stackoverflow.com/', 
    'http://sstatic.net/so/img/logo.png', 
    'http://www.gravatar.com/avatar/212151980ba7123c314251b185608b1d?s=128&d=identicon&r=PG', 
    'http://de.php.net/images/php.gif' 
); 

$data = array(); 
$fnWrite = function($ch, $chunk) use(&$data) { 
    foreach($data as $d) { 
    if ($ch===$d['curlrc']) { 
     hash_update($d['hashrc'], $chunk); 
    } 
    } 
}; 

$mh = curl_multi_init(); 
foreach($urls as $u) { 
    $current = curl_init(); 
    curl_setopt($current, CURLOPT_URL, $u); 
    curl_setopt($current, CURLOPT_RETURNTRANSFER, 0); 
    curl_setopt($current, CURLOPT_HEADER, 0); 
    curl_setopt($current, CURLOPT_WRITEFUNCTION, $fnWrite); 
    curl_multi_add_handle($mh, $current); 
    $hash = hash_init('md5'); 
    $data[] = array('url'=>$u, 'curlrc'=>$current, 'hashrc'=>$hash); 
} 

$active = null; 
//execute the handles 
do { 
    $mrc = curl_multi_exec($mh, $active); 
} while ($mrc == CURLM_CALL_MULTI_PERFORM); 

while ($active && $mrc == CURLM_OK) { 
    if (curl_multi_select($mh) != -1) { 
    do { 
     $mrc = curl_multi_exec($mh, $active); 
    } while ($mrc == CURLM_CALL_MULTI_PERFORM); 
    } 
} 

foreach($data as $d) { 
    curl_multi_remove_handle($mh, $d['curlrc']); 
    echo $d['url'], ': ', hash_final($d['hashrc'], false), "\n"; 
} 
curl_multi_close($mh); 

(還沒有檢查的結果,雖然......這只是一個起點)

+2

+1。並行下載可能是一個巨大的勝利。你也可以通過使用'md5sum' CLI命令(例如'exec('bash -c「md5sum file1> file1.md5&'')'),或者使用類似PHP的pcntl_fork()來實現md5部分的並行化。將多個調用分叉到md5_sum()。這些都有它們的缺點,但是在正確的背景下,它們可能是最好的選擇。 – 2010-05-01 15:01:23

+0

我必須承認,我甚至沒有測試下載是否真的繼續執行回調。但由於數據部分應該很小,所以我希望它不重要(很多)。 – VolkerK 2010-05-01 15:26:05

0

md5算法的速度幾乎可以達到,獲取網址的速度幾乎可以達到(如果文件很大或連接速度較慢,速度會變慢)。所以不行。你無法讓速度更快。

0

那麼顯然,你不能做md5_file()任何事情,使速度更快,但是,你可以使用一些micro-optimizations或代碼重新分解得到一些速度增益,但你又不能加快內置函數md5_file()

+1

......當然,一些微型優化可能會削減2毫秒的運行時間。也許。或者他可以並行拖動網址並保存幾秒鐘。 「微觀優化」幾乎是不值得的。 – 2010-05-01 14:57:54

+0

@Frank,這是在編輯問題之前發佈的,它實際上包含了問題代碼(直到添加代碼之前,基本上詢問如何加速md5_file())。 – 2010-05-01 15:16:06

0

不可以。因爲這是內置函數,所以無法使其更快。

但是,如果您的代碼在MD5之前下載文件,可能會優化您的下載速度。如果您事先知道大小,則在寫入文件之前(使用ftruncate)設置文件的大小也可能會看到小的速度增加。另外,如果文件足夠小以容納內存,並且你已經將它們存儲在內存中(因爲它們已經被下載,或者正在爲其他目的而被讀取),那麼你可以使用md5在內存中對其進行操作而不是md5_file,這需要從磁盤再次讀取。

0

假設您在一段時間內檢查了相同的URL?你可以檢查URL的最後修改標題嗎?如果被檢查的頁面沒有改變,那麼就不需要重新計算MD5。

您也可以異步請求頁面,以便它們可以並行處理,而不是以串行方式處理,這會加快處理速度。

0

MD5算法的速度是線性的。輸入越大,需要的時間就越多,所以如果文件很大,真的沒有太多可以做的事情。

現在,正如VolkerK已經提出的那樣,問題很可能不是md5散列,而是通過網絡檢索和讀取文件。

0

我看到一個非常好的建議,優化here。這對於大文件尤其適用,其中md5_file正在讀取文件,而此函數僅比較每個文件的第二個字節。

0

解釋你想要做什麼會有所幫助。 如果你想驗證文件的MD5散列:

這不是一個安全的方法,因爲它很容易Collision attack。您應該使用多個哈希(可能通過分割文件)或使用其他哈希方法。