2013-05-27 5 views
12

позволяет сказать, у меня есть 64-ядерный сервер, и мне нужно вычислить md5sum все файлы в /mnt/data и сохранить результаты в текстовом файле:Bash: распараллеливание md5sum контрольной суммы многих файлов

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

Проблема с приведенной выше командой заключается в том, что в любой момент времени выполняется только один процесс. Я хотел бы использовать всю мощь своих 64-ядер. В идеале я хотел бы убедиться, что в любой момент времени выполняется 64 параллельных процесса md5 (но не более 64).

Также. Мне понадобится вывод из всех процессов, которые нужно сохранить в один файл.

ПРИМЕЧАНИЕ: Я не ищу способ вычисления md5sum одного файла параллельно. Я ищу способ вычислить 64 md5sums из 64 различных файлов параллельно, если есть файлы, поступающие от find.

+5

Я не уверен, что это будет хорошо. Я мог представить, что материал скоро будет привязан к IO, и что использование 64 процессов приведет к slooow IO, хотя многие ядра остаются бездействующими. – glglgl

+0

Но, с другой стороны, современные файловые системы много кэшируются в ОЗУ, поэтому использование более чем одного за раз имеет смысл. – Alfe

+1

@Alfe: ядро ​​все равно придется извлекать данные * в * ОЗУ, поэтому узкое место остается. –

ответ

16

Использование GNU parallel. И вы можете найти еще несколько примеров того, как его реализовать. here.

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

Я не знал, что GNU параллельна. Спасибо, что упомянул об этом. Однако мне нужно будет увидеть, полезно ли это в моем случае. На данный момент 'time find/mnt/data -type f | parallel -j 16 md5sum> md5.txt' примерно в 3 раза медленнее, чем обычно, find 'time find/usr/share -type f -exec md5sum {} \; > md5.txt'. – user1968963

1

ОБНОВЛЕНО

Если Вы не хотите использовать дополнительные пакеты можно попробовать SG, как это:

#!/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 

Это первый позволяет получить SIGCHLD, если Подпроцесса выходов. Если SIGCHLD находит первый несуществующий процесс и удаляет из массива cpid.

В течение цикла он начинается max Число some_long_process обрабатывается асинхронно. Это max достигло опросов всех добавленных к cpid массивов. Он ждет, пока длина cpid будет меньше max и начнет несколько процессов асинхронно.

Если список окончен, он ждет завершения всех детей.

ДОБАВЛЕНО

Наконец я нашел правильное решение here.

+0

Спасибо за скрипт. К сожалению, это не приносит никакого улучшения. Действительно, время больше, чем при простой находке. Кроме того, большинство ядер, похоже, простаивают. Мне придется экспериментировать, если я могу его подделать. – user1968963

+0

@ user1968963: Может быть, строка 'sleep 1' может быть удалена. Он будет излишне загружать одно ядро. Попробуйте это. Возможно, вы могли бы немного улучшить использование 'find/mnt/data -type f -exec md5sum {} +> md5.txt'. Обратите внимание на конечную '+' вместо ';'! Это вызовет 'md5sum' гораздо меньше раз. (см. '-exec command {} +' в [find (1)] (http://linux.die.net/man/1/find)). – TrueY

6

Если вы хотите экспериментировать, попробуйте установить md5deep. (http://md5deep.sourceforge.net)

Here is the manual, где вы можете прочитать:

-jnn Controls многопоточность. По умолчанию программа создаст один поток производителей для сканирования файловой системы и одного потока хеширования на процессор ядра . Многопоточность приводит к тому, что имена выходных файлов должны быть в недетерминированным порядком, поскольку файлы, которые занимают больше времени для хэша, будут задерживаться, пока они хэшируются. Если требуется детерминированный порядок, указать -j0 отключить многопоточность

Если это не помогает, то есть узкие места ввода/вывода.

4

Вы также можете использовать xargs, он может быть более доступным, чем параллели на некоторых дистрибутивах.

-P контролирует количество процессов, порожденных.

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

Предоставленный ответ не работает, когда имена файлов содержат пробелы. Правильный один из них следующий, также с использованием переключателей POSIX: «find/mnt/data -type f -print0 | xargs -L1 -P24 -0 md5> /tmp/result.txt» Вы также можете использовать параметр -r для md5, чтобы отменить вывод и получить контрольную сумму до пути, чтобы вы могли заказать контрольную сумму и легко найти дубликаты. – FarO

+1

@OlafM Я уже исправил этот вопрос, как вы можете видеть. – Braiam

+0

@Braiam это все равно не будет работать на имена файлов, содержащих пробелы. Те, кому нужно «-print0» и «-0», разделять вывод не в соответствии с пробелами (возможно, в именах файлов), а в соответствии с нулевыми символами. – FarO