Attualmente utilizzo md5_file()
per eseguire circa 15 URL e verificare gli hash MD5. C'è un modo per renderlo più veloce? Ci vuole troppo tempo per attraversarli tutti.Un modo per rendere md5_file() più veloce?
risposta
Probabilmente lo stai facendo in sequenza proprio adesso. Cioè recuperare i dati 1, elaborare i dati 1, recuperare i dati 2, elaborare i dati 2, ... e il collo di bottiglia potrebbe essere il trasferimento dei dati.
Si potrebbe usare curl_multi_exec() per parallelizzare un po '. Registra uno CURLOPT_WRITEFUNCTION ed elabora ogni blocco di dati (difficile dal momento che md5() funziona esattamente su un blocco di dati).
Oppure controllare gli handle di arricciatura che sono già finiti e quindi elaborare i dati di quella maniglia.
modifica: pratica & esempio sporco usando l'hash extension (che fornisce le funzioni di hash incrementali) e un 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);
(non hanno verificato i risultati però ... è solo un punto di partenza)
+1. Parallelamente i download sono probabilmente una grande vittoria qui. Si potrebbe anche parallelizzare la porzione md5, usando il comando CLI 'md5sum' (es.' Exec ('bash -c "md5sum file1> file1.md5 e"') '), o usando qualcosa come il pcntl_fork di PHP() forporre più chiamate a md5_sum(). Entrambi hanno i loro svantaggi, ma nel contesto giusto potrebbero essere la cosa migliore da fare. –
E devo ammettere che non ho ancora testato se il download continua davvero mentre viene eseguito il callback. Ma dal momento che le porzioni di dati sono presumibilmente piccole, spero che non importi (molto). – VolkerK
L'algoritmo MD5 è praticamente il più veloce possibile e recuperare gli URL è praticamente il più veloce possibile (lento se i file sono enormi o se la connessione è lenta). Quindi no. Non puoi renderlo più veloce.
Beh, ovviamente, non si può fare qualsiasi cosa con md5_file()
per rendere più veloce, tuttavia, è possibile utilizzare alcuni micro-optimizations o il codice di ri-factoring per ottenere qualche guadagno di velocità, ma ancora una volta non si può accelerare la funzione built-in md5_file()
.
... Certo, alcune micro-ottimizzazioni potrebbero radere 2 millisecondi del suo runtime. Può essere. O potrebbe semplicemente tirare gli URL in parallelo e salvare qualche secondo. "Micro-ottimizzazioni" non valgono quasi mai lo sforzo. –
@Frank, Questo è stato pubblicato prima della modifica della domanda per includere effettivamente il codice in questione (che, fino a quando non è stato aggiunto il codice, in pratica chiedeva come accelerare md5_file()). –
No. Poiché questa è una funzione incorporata, non c'è modo di renderla più veloce.
Tuttavia, se il codice sta scaricando file prima di MD5, è possibile ottimizzare i download per essere più veloci. Potresti anche vedere un piccolo aumento di velocità impostando la dimensione del file (usando ftruncate) prima di scriverlo se conosci la dimensione in anticipo.
Inoltre, se i file sono abbastanza piccoli da contenere in memoria e sono già presenti nella memoria (perché sono stati scaricati o letti per altri scopi), è possibile utilizzare md5
per operare su di esso in memoria piuttosto che md5_file
che richiede di essere riletto dal disco.
Presumibilmente stai controllando gli stessi URL per un periodo di tempo? Potresti controllare le ultime intestazioni modificate per l'URL? Se la pagina che si sta verificando non è cambiata, non ci sarà bisogno di ricalcolare l'MD5.
È anche possibile richiedere le pagine in modo asincrono in modo che possano essere elaborate in parallelo, anziché in serie, il che dovrebbe velocizzarlo.
La velocità dell'algoritmo MD5 è lineare. Più grande è l'input, più tempo ci vorrà, quindi se il file è grande, non c'è molto che tu possa fare, davvero.
Ora, come già suggerito da VolkerK, probabilmente il problema non è l'hashing md5 ma il recupero e la lettura del file attraverso la rete.
Vedo un ottimo suggerimento di ottimizzazione here. Questo funzionerà bene specialmente per i file di grandi dimensioni, dove md5_file sta leggendo il file e questa funzione sta solo confrontando il secondo byte di ciascun file.
Spiegare cosa si vuole fare sarebbe d'aiuto. Nel caso in cui si desidera verificare un file con i loro hash MD5:
Non è un metodo sicuro in quanto è soggetta a Collision attack. Dovresti usare più hash (magari suddividendo il file) o usando altri metodi hash.
"esegui circa 15 URL" significa qualcosa come 'md5_file ('http: //some.url/foo')' in un ciclo con 15 URL diversi? Quanto sono grandi questi "file"? – VolkerK
Sì, è esattamente così. Li tiro da un database MySQL e poi li eseguo in md5_file ($ result) in un ciclo. I file sono MOLTO piccoli e in effetti non hanno output di visualizzazione, nessuna interfaccia utente, solo una pagina bianca vuota quando visualizzata – Rob
Il problema è che stai calcolando gli hash in sequenza piuttosto che in parallelo; 'md5_file' non è il collo di bottiglia. Inoltre, sicuramente l'hash di un file vuoto sarà sempre lo stesso. – salathe