Одночасно обчислювати декілька дайджестів (md5, sha256)?


25

Припускаючи, що введення / виведення диска та вільна оперативна пам’ять є вузьким місцем (хоча час процесора не є обмеженням), чи існує інструмент, який може обчислити кілька дайджестів повідомлень одночасно?

Мене особливо цікавить обчислення дайджестів великих файлів MD-5 та SHA-256 (розмір у гігабайти), бажано паралельно. Я спробував openssl dgst -sha256 -md5, але він обчислює хеш лише за допомогою одного алгоритму.

Псевдокод очікуваної поведінки:

for each block:
    for each algorithm:
        hash_state[algorithm].update(block)
for each algorithm:
    print algorithm, hash_state[algorithm].final_hash()

Ви можете просто запустити один екземпляр у фоновому режимі, тоді обидва хеші працюють паралельно:for i in file1 file2 …; do sha256 "$i"& md5sum "$i"; done
Марко,

2
@Marco Проблема такого підходу полягає в тому, що одна команда може бути швидшою, ніж інша, в результаті чого кеш диска, який випорожняється і наповнюється згодом тими ж даними.
Лекенштейн

1
Якщо ви переживаєте за кеш диска, ви можете прочитати у файлі лише один раз: for i in file1 file2 …; do tee < "$i" >(sha256sum) | md5sum ; doneТоді вам потрібно додати додатковий код, щоб позначити ім'я файлу, оскільки він надсилається як стандартний вхід до md5sumта sha256sum.
Марко

Відповіді:


28

Виїзд pee(" tee standard input to pipes") з moreutils. Це в основному еквівалентно teeкоманді Марко , але трохи простіше набрати.

$ echo foo | pee md5sum sha256sum
d3b07384d113edec49eaa6238ad5ff00  -
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c  -
$ pee md5sum sha256sum <foo.iso
f109ffd6612e36e0fc1597eda65e9cf0  -
469a38cb785f8d47a0f85f968feff0be1d6f9398e353496ff7aa9055725bc63e  -

Гарна команда! Я вже встановив цей дуже корисний пакет, не знав про цю кумедну утиліту.
Лекенштейн

1
peeнайкращий інтерфейс, порівняння часу з іншими інструментами можна знайти у цій публікації, яка також демонструє багатопотоковий інструмент Python.
Лекенштейн

На жаль, moreutilsконфлікти з GNU parallelмоєю системою Debian… хоча добре знати, що є такий інструмент.
liori

@Lekensteyn: У мене конфлікт на рівні пакету (тобто aptitudeне дозволяє мені мати обидва пакети одночасно).
liori

@liori Шкода, що Debian його реалізував саме так, можливо, варто помилитися з цим. У Arch Linux є moreutils-parallelназва, щоб уникнути конфлікту.
Лекенштейн

10

Ви можете використовувати forцикл для циклу на окремих файлах, а потім використовувати в tee поєднанні з підстановкою процесів (працює в Bash і Zsh серед інших) для передачі на різні контрольні суми.

Приклад:

for file in *.mkv; do
  tee < "$file" >(sha256sum) | md5sum
done

Ви також можете використовувати більше двох контрольних сум:

for file in *.mkv; do
  tee < "$file" >(sha256sum) >(sha384sum) | md5sum
done

Це має той недолік, що контрольні суми не знають імені файлу, оскільки він передається як стандартний вхід. Якщо це не прийнятно, ви повинні випромінювати імена файлів вручну. Повний приклад:

for file in *.mkv; do
  echo "$file"
  tee < "$file" >(sha256sum) >(sha384sum) | md5sum
  echo
done > hashfilelist

1
Щоб зробити висновок сумісним із *sumсімейством інструментів, замість цього можна використати це вираження sed: sed "s;-\$;${file//;/\\;};(замінив трейлінг -на ім'я файлу, але переконайся, що ім'я файлу належним чином уникне).
Лекенштейн

AFAICS, він працює лише в zsh. У ksh93 та bash вихід sha256sum переходить до md5sum. Ви хочете: { tee < "$file" >(sha256sum >&3) | md5sum; } 3>&1. Див. Unix.stackexchange.com/q/153896/22565 для зворотної проблеми.
Стефан Шазелас

6

Шкода, що утиліта openssl не приймає декілька команд дайджесту; Я думаю, що одна і та ж команда на декількох файлах є більш поширеною схемою використання. FWIW, версія утиліти openssl в моїй системі (Mepis 11) містить лише команди для sha і sha1, не будь-який з інших варіантів ша. Але в мене є програма під назвою sha256sum, а також md5sum.

Ось проста програма Python, dual_hash.py, яка робить те, що ви хочете. Розмір блоку 64k здається оптимальним для моєї машини (Intel Pentium 4 2.00GHz з 2G оперативної пам’яті), YMMV. Для невеликих файлів його швидкість приблизно така сама, як підряд md5sum та sha256sum підряд. Але для великих файлів це значно швидше. Наприклад, у байтовому файлі 1967063040 (зображення диска SD-карти, наповненої mp3-файлами) md5sum + sha256sum займає близько 1m44,9s, dual_hash.py займає 1m0,312s.

dual_hash.py

#! /usr/bin/env python

''' Calculate MD5 and SHA-256 digests of a file simultaneously

    Written by PM 2Ring 2014.10.23
'''

import sys
import hashlib

def digests(fname, blocksize):
    md5 = hashlib.md5()
    sha = hashlib.sha256()
    with open(fname, 'rb') as f:
        while True:
            block = f.read(blocksize)
            if not block:
                break
            md5.update(block)
            sha.update(block)

    print("md5: %s" % md5.hexdigest())
    print("sha256: %s" % sha.hexdigest())

def main(*argv):
    blocksize = 1<<16 # 64kB
    if len(argv) < 2:
        print("No filename given!\n")
        print("Calculate md5 and sha-256 message digests of a file.")
        print("Usage:\npython %s filename [blocksize]\n" % sys.argv[0])
        print("Default blocksize=%d" % blocksize)
        return 1

    fname = argv[1]

    if len(argv) > 2:
        blocksize = int(sys.argv[2])

    print("Calculating MD5 and SHA-256 digests of %r using a blocksize of %d" % (fname, blocksize))
    digests(fname, blocksize)

if __name__ == '__main__':
    sys.exit(main(*sys.argv))

Я вважаю , версія С / С ++ цієї програми буде трохи швидше, але не так багато, так як більша частина роботи робиться модулем hashlib, який буде написаний на C (або C ++). І як ви зазначали вище, вузьким місцем для великих файлів є швидкість IO.


Для файлу 2.3G, ця версія була вже порівнянна швидкість по порівнянні з md5sumі в sha256sumпоєднанні (4.7s + 14.2s проти 18.7s для цього Python скрипта, файл в кеші, 33.6s для холодного запуску). 64KiB проти 1MiB ситуацію не змінили. При коментованому коді 5,1s було витрачено на md5 (n = 3), 14,6 на sha1 (n = 3). Тестовано на i5-460M з 8 Гб оперативної пам’яті. Я здогадуюсь, що це можна було б покращити, використовуючи більше ниток.
Лекенштейн

C або C ++, мабуть, не має значення, що стільки ж часу виконання буде витрачено в модулі OpenSSL так чи інакше (використовується хешлібом). Більше потоків покращує швидкість, дивіться цю публікацію про багатопотоковий сценарій Python .
Лекенштейн

@PM 2Ring - Просто примітка. Після друку тверджень у вашій функції digests () вам потрібно очистити принаймні sha. Я не можу сказати, чи слід очищати md5 чи ні. Я б просто скористався "дель ша". Якщо цього не зробити, кожен файл після першого буде мати неправильний хеш. Щоб довести це, зробіть tmp dir та скопіюйте у нього файл. Тепер зробіть 2 копії цього файлу та запустіть свій сценарій. Ви отримаєте 3 різних хеши, що не те, що ви хочете. Редагувати: Я думав, що функція читає набір файлів, а не просто читає один файл за один раз ... Нехтування цим використанням. ;)
Террі Вендт

1
@TerryWendt Ти мене хвилював там на секунду. :) Так, digestsобробляє лише один файл під час кожного дзвінка. Тож навіть якщо ви його зателефонували в циклі, він створюватиме нові контексти md5 & sha на кожному дзвінку. FWIW, вам може сподобатися мій поновлюваний хеш SHA-256 .
PM 2Ring

5

Ви завжди можете використовувати щось на зразок паралельної GNU :

echo "/path/to/file" | parallel 'md5sum {} & sha256sum {}'

Крім того, просто запустіть один із двох у фоновому режимі:

md5sum /path/to/file & sha256sum /path/to/file

Або збережіть вихід у різних файлах і виконайте кілька завдань у фоновому режимі:

for file in *; do
    md5sum "$file" > "$file".md5 &
    sha256sum "$file" > "$file".sha &
done

Це запустить стільки md5sumі sha256sumекземплярів, скільки у вас є файлів, і всі вони працюватимуть паралельно, зберігаючи свій вихід у відповідні назви файлів. Якщо обережно, це може стати важким, якщо у вас багато файлів.


1
Дивіться коментар до Марко, я хвилююсь, що хоча команда буде паралельною, повільний диск отримує доступ до тих же даних двічі.
Лекенштейн

Але чи не існування кеш-диска не зробить ваших турбот непотрібними?
Мерехтіння

2
@Twinkles Цитуючи Лекенштейна вище, "Проблема такого підходу полягає в тому, що одна команда може бути швидшою за іншу, в результаті чого кеш-диск буде випорожнено і пізніше заповнений тими ж даними".
Метт Нордхофф

2
@MattNordhoff Ще одна річ, яку повинен помітити та оптимізувати інтелектуальний планувальник вводу-виводу. Можна подумати: "Наскільки важко планувальнику вводу / виводу врахувати цей сценарій?" Але з достатньо різними сценаріями, які планувальник вводу-виводу повинен враховувати, це раптом стає важкою проблемою. Тож я погоджуюся, що не слід вважати, що кешування вирішить проблему.
kasperd

1
Якщо припустити, що IO значно повільніше, ніж будь-який із залучених інструментів, обидва інструменти повинні бути сповільнені до однакової швидкості через IO. Тому, якщо одному інструменту вдасться отримати кілька блоків даних більше, ніж інший, інший інструмент швидко наздожене обчислення, використовуючи дані в дисковому кеші. Це теорія, я хотів би побачити деякі експериментальні результати, що підтверджують це…
liori

3

З цікавості, чи скоротить багатопотоковий скрипт Python, я створив цей digest.pyсценарій, який використовує threading.Thread, threading.Queueта hashlibобчислив хеші для декількох файлів.

Реалізація багатопотокового Python дійсно трохи швидша, ніж використання peeз coreutils. Java з іншого боку - це ... мех. Результати доступні в цьому повідомленні про виконання зобов'язань :

Для порівняння, для файлу розміром 2,3 Гб (хв / avg / max / sd сек для n = 10):

  • pee sha256sum md5sum <файл: 16.5 / 16.9 /17.4/.305
  • python3 digest.py -sha256 -md5 <файл: 13.7 / 15.0 /18.7/1.77
  • python2 digest.py -sha256 -md5 <файл: 13.7 / 15.9 /18.7/1.64
  • jacksum -a sha256 + md5 -F '#CHECKSUM {i} #FILENAME': 32.7 / 37.1 / 50 / 6.91

Хеш-вихід сумісний з результатами, що виробляються coreutils. Оскільки довжина залежить від алгоритму хешування, цей інструмент не друкує його. Використання (для порівняння peeтакож було додано):

$ ./digest.py -sha256 -md5 digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  digest.py
b575edf6387888a68c93bf89291f611c  digest.py
$ ./digest.py -sha256 -md5 <digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  -
b575edf6387888a68c93bf89291f611c  -
$ pee sha256sum md5sum <digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  -
b575edf6387888a68c93bf89291f611c  -

Я збирався запропонувати порівняти pee "openssl sha256" "openssl md5" < file, але, чесно кажучи, я просто спробував це, і це не перемогло digest.py. Однак це звузило розрив.
Метт Нордхофф

1

Jacksum - це безкоштовна і незалежна від платформи утиліта для обчислення та перевірки контрольних сум, CRC та хешей (дайджестів повідомлень), а також часових міток файлів. ( уривок із сторінки "jacksum man" )

Це великий файл, він може обробляти розміри файлів до 8 екзабайт (= 8 000 000 000 гігабайт), припускаючи, що ваша операційна система, відповідно, ваша файлова система також знає великі файли. (уривок із http://www.jonelo.de/java/jacksum/ )

Приклад використання:

jacksum -a md5+sha256 -F "#ALGONAME{i} (#FILENAME) = #CHECKSUM{i}" jacksum-testfile

Вибірка зразка:

md5 (jacksum-testfile) = d41d8cd98f00b204e9800998ecf8427e
sha256 (jacksum-testfile) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

У ubuntu запустіть команду, apt-get install jacksumщоб отримати його.

Крім того, вихідні коди доступні за адресою


Хоча це робить правильні контрольні суми, ця програма Java обчислює вдвічі повільніше, ніж coreutils. Дивіться це повідомлення про фіксацію .
Лекенштейн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.