Bash: параллельная контрольная сумма md5sum для многих файлов

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

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

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

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

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

Ответ 1

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

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

Ответ 2

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

Вот руководство, в котором вы можете прочитать:

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

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

Ответ 3

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

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

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

Ответ 4

ОБНОВЛЕНО

Если вы не хотите использовать дополнительные пакеты, вы можете попробовать 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.

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

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

ADDED

Наконец, я нашел правильный make solution здесь.