2013-05-27 13 views
12

consente di dire, ho un server a 64-core, e ho bisogno di calcolare md5sum di tutti i file in /mnt/data, e memorizzare i risultati in un file di testo:Bash: parallelizzare md5sum checksum su molti file

find /mnt/data -type f -exec md5sum {} \; > md5.txt 

Il problema con il comando precedente è che solo un processo viene eseguito in un dato momento. Vorrei sfruttare tutta la potenza dei miei 64 core. Idealmente, vorrei assicurarmi che in qualsiasi momento siano in esecuzione 64 processi paralleli md5 (ma non più di 64).

anche. Avrei bisogno dell'output di tutti i processi da memorizzare in un unico file.

NOTA: non sto cercando un modo per calcolare md5sum di un file in parallelo. Sto cercando un modo per calcolare 64 md5sum di 64 file diversi in parallelo, a patto che ci siano file provenienti da find.

+5

io non sono sicuro che questo sarà un bene. Potrei immaginare che la roba diventerà IO legata molto presto e che l'uso di 64 processi porterà a slooow IO pur avendo molti core in riposo. – glglgl

+0

Ma d'altra parte, i file system moderni sono memorizzati molto nella RAM, quindi usare più di uno alla volta ha senso. – Alfe

+1

@Alfe: il kernel dovrà comunque recuperare i dati * in * RAM, quindi il collo di bottiglia rimane. –

risposta

16

Utilizzare GNU parallel. E puoi trovare altri esempi su come implementarlo here.

find /mnt/data -type f | parallel -j 64 md5sum > md5.txt 
+1

Non conoscevo il parallelo GNU. Grazie per averlo menzionato. Dovrò vedere se è utile nel mio caso, però. Al momento, 'tempo trovare/mnt/data-tipo f | parallel -j 16 md5sum> md5.txt' è circa 3 volte più lento del normale find 'time find/usr/share -type f -exec md5sum {} \; > md5.txt'. – user1968963

1

AGGIORNATO

Se non si desidera utilizzare pacchetti aggiuntivi Si può provare sg come questo:

#!/usr/bin/bash 

max=5; 
cpid=() 

# Enable job control to receive SIGCHLD 
set -m 
remove() { 
    for i in ${!cpid[*]}; do 
    [ ! -d /proc/$i ] && echo UNSET $i && unset cpid[$i] && break 
    done 
} 
trap remove SIGCHLD 

for x in $(find ./ -type f -name '*.sh'); do 
    some_long_process $x& 
    cpid[$!]="$x"; 
    while [ ${#cpid[*]} -ge $max ]; do 
    echo DO SOMETHING && sleep 1; 
    done 
done 
wait 

Permette primi a ricevere SIGCHLD se un sottoprocesso uscite. Se SIGCHLD trova il primo processo non esistente e rimuove dall'array cpid.

Nel ciclo for si avvia max numero di processi some_long_process in modo asincrono. È stato raggiunto il numero max e vengono interrogati tutti i pid aggiunti all'array cpid. Aspetta fino a quando la lunghezza di cpid è inferiore a max e avvia alcuni altri processi in modo asincrono.

Se la lista è finita, aspetta che tutti i bambini finiscano.

AGGIUNTO

Finalmente ho trovato una vera e propria soluzione di here.

+0

Grazie per la sceneggiatura. Sfortunatamente, non porta alcun miglioramento. In effetti, il tempo è più lungo che con la ricerca semplice. Inoltre, la maggior parte dei nuclei sembra essere inattiva. Dovrò sperimentare, se posso farlo. – user1968963

+0

@ user1968963: Forse la riga 'sleep 1' potrebbe essere rimossa. Caricherà inutilmente un core. Prova in questo modo. Forse potresti migliorare un po 'usando 'find/mnt/data -type f -exec md5sum {} +> md5.txt'. Mente il trailing '+' invece di ';'! Questo chiamerà 'md5sum' molto meno volte. (vedi '-exec command {} +' in [find (1)] (http://linux.die.net/man/1/find)). – TrueY

6

Se si desidera eseguire l'esperimento, provare a installare md5deep. (http://md5deep.sourceforge.net)

Here is the manual dove si può leggere:

-jnn Controlli multi-threading. Per impostazione predefinita, il programma creerà un thread di produzione per eseguire la scansione del file system e un thread di hashing per CPU core . Il multithreading fa sì che i nomi dei file di uscita siano nell'ordine non deterministico , poiché i file che richiedono più tempo per l'hash saranno ritardati mentre sono sottoposti a hash. Se è necessario un ordine deterministico, specificare -j0 per disabilitare il multi-threading

Se questo non aiuta, si dispone di collo di bottiglia I/O.

4

È possibile utilizzare anche xargs, potrebbe essere più disponibile dei paralleli su alcune distribuzioni.

-P controlla il numero di processi generati.

find /mnt/data -type f | xargs -L1 -P24 md5sum > /tmp/result.txt 
+1

La risposta fornita non sembra funzionare quando i nomi dei file contengono spazi. Quello corretto è il seguente, utilizzando anche gli switch POSIX: "find/mnt/data -type f -print0 | xargs -L1 -P24 -0 md5> /tmp/result.txt" Si può anche voler usare l'opzione -r per md5 per invertire l'output e ottenere il checksum PRIMA del percorso, in modo da poter ordinare per checksum e trovare facilmente i duplicati. – FarO

+1

@OlafM Ho già risolto il problema, come puoi vedere. – Braiam

+0

@Braiam continua a non funzionare sui nomi di file contenenti spazi. Quelli in particolare hanno bisogno di "-print0" e "-0" per dividere l'output non in base agli spazi bianchi (potenzialmente all'interno dei nomi di file) ma in base ai caratteri nulli. – FarO