Đồng thời tính toán nhiều tiêu hóa (md5, sha256)?


24

Theo giả định rằng I / O đĩa và RAM miễn phí là một nút cổ chai (trong khi thời gian CPU không phải là giới hạn), liệu một công cụ có tồn tại có thể tính toán nhiều thông báo tiêu hóa cùng một lúc không?

Tôi đặc biệt quan tâm đến việc tính toán các bản tóm tắt MD-5 và SHA-256 của các tệp lớn (kích thước tính bằng gigabyte), tốt nhất là song song. Tôi đã thử openssl dgst -sha256 -md5, nhưng nó chỉ tính toán hàm băm bằng một thuật toán.

Mã giả cho hành vi dự kiến:

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

Bạn chỉ có thể bắt đầu một phiên bản trong nền, sau đó cả hai băm chạy song song:for i in file1 file2 …; do sha256 "$i"& md5sum "$i"; done
Marco

2
@Marco Vấn đề với cách tiếp cận đó là một lệnh có thể nhanh hơn lệnh kia, dẫn đến bộ đệm đĩa bị xóa và được nạp lại sau đó với cùng một dữ liệu.
Lekensteyn

1
Nếu bạn lo lắng về bộ đệm đĩa, bạn có thể đọc trong tệp chỉ một lần: for i in file1 file2 …; do tee < "$i" >(sha256sum) | md5sum ; doneSau đó, bạn phải thêm mã bổ sung để đánh dấu tên tệp, vì nó được gửi dưới dạng đầu vào tiêu chuẩn md5sumsha256sum.
Marco

Câu trả lời:


28

Kiểm tra pee(" tee standard input to pipes") từ moreutils. Điều này về cơ bản tương đương với teelệnh của Marco , nhưng gõ đơn giản hơn một chút.

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

Lệnh hay! Tôi đã cài đặt gói rất hữu ích này, không biết tiện ích có tên ngộ nghĩnh này.
Lekensteyn

1
peecó giao diện tốt nhất, so sánh thời gian với các công cụ khác có thể được tìm thấy trong bài viết này cũng cho thấy một công cụ Python đa luồng.
Lekensteyn

Thật không may, moreutilsxung đột với GNU parallelhệ thống Debian của tôi, tuy nhiên, thật tốt khi biết có một công cụ như vậy.
liori

@Lekensteyn: Tôi nhận được một cuộc xung đột ở cấp độ gói (nghĩa là aptitudekhông cho phép tôi có cả hai gói cùng một lúc).
liori

@liori Thật tệ khi Debian triển khai nó theo cách đó, có thể đáng để gửi một lỗi về điều này. Trên Arch Linux có một moreutils-parallelcái tên để tránh xung đột.
Lekensteyn

10

Bạn có thể sử dụng một forvòng lặp để lặp qua các tệp riêng lẻ và sau đó sử dụng tee kết hợp với thay thế quy trình (hoạt động trong Bash và Zsh trong số các tệp khác) để chuyển sang các bộ kiểm tra khác nhau.

Thí dụ:

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

Bạn cũng có thể sử dụng nhiều hơn hai bộ kiểm tra:

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

Điều này có nhược điểm là người kiểm tra không biết tên tệp, vì nó được thông qua dưới dạng đầu vào tiêu chuẩn. Nếu điều đó không được chấp nhận, bạn phải phát tên tệp theo cách thủ công. Ví dụ hoàn chỉnh:

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

1
Để làm cho đầu ra tương thích với *sumhọ công cụ, biểu thức sed này có thể được sử dụng thay thế: sed "s;-\$;${file//;/\\;};(thay thế dấu vết -bằng tên tệp, nhưng đảm bảo rằng tên tệp được thoát đúng).
Lekensteyn

AFAICS, nó chỉ hoạt động trong zsh. Trong ksh93 và bash, đầu ra của sha256sum chuyển đến md5sum. Bạn sẽ muốn : { tee < "$file" >(sha256sum >&3) | md5sum; } 3>&1. Xem unix.stackexchange.com/q/153896/22565 để biết vấn đề ngược lại.
Stéphane Chazelas

6

Thật đáng tiếc khi tiện ích openssl không chấp nhận nhiều lệnh digest; Tôi đoán thực hiện cùng một lệnh trên nhiều tệp là một mẫu sử dụng phổ biến hơn. FWIW, phiên bản của tiện ích openssl trên hệ thống của tôi (Mepis 11) chỉ có các lệnh cho sha và sha1, không có bất kỳ biến thể sha nào khác. Nhưng tôi có một chương trình gọi là sha256sum, cũng như md5sum.

Đây là một chương trình Python đơn giản, dual_hash.py, thực hiện những gì bạn muốn. Kích thước khối 64k dường như là tối ưu cho máy của tôi (Intel Pentium 4 2.00GHz với 2G RAM), YMMV. Đối với các tệp nhỏ, tốc độ của nó gần tương đương với việc chạy md5sum và sha256sum liên tiếp. Nhưng đối với các tệp lớn hơn thì nhanh hơn đáng kể. Ví dụ: trên tệp byte 1967063040 (hình ảnh đĩa của thẻ SD chứa đầy tệp mp3), md5sum + sha256sum mất khoảng 1m44.9s, dual_hash.py mất 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))

Tôi cho rằng một phiên bản C / C ++ của chương trình này sẽ nhanh hơn một chút, nhưng không nhiều, vì hầu hết các công việc đang được thực hiện bởi mô-đun hashlib, được viết bằng C (hoặc C ++). Và như bạn đã lưu ý ở trên, nút cổ chai cho các tệp lớn là tốc độ IO.


Đối với tệp 2.3G, phiên bản này có tốc độ tương đương so với md5sumsha256sumkết hợp (4,7 giây + 14,2 giây so với 18,7 giây đối với tập lệnh Python này, tệp trong bộ đệm; 33,6 giây cho chạy lạnh). 64KiB so với 1MiB không thay đổi tình hình. Với mã nhận xét, 5.1s đã được chi cho md5 (n = 3), 14.6s cho sha1 (n = 3). Đã thử nghiệm trên i5-460M với RAM 8GB. Tôi đoán rằng điều này có thể được cải thiện hơn nữa bằng cách sử dụng nhiều chủ đề hơn.
Lekensteyn

C hoặc C ++ có thể sẽ không quan trọng bằng việc phần lớn thời gian chạy được sử dụng trong mô-đun OpenSSL (được sử dụng bởi hashlib). Nhiều chủ đề không cải thiện tốc độ, xem bài đăng này về một tập lệnh Python đa luồng .
Lekensteyn

@PM 2Ring - Chỉ là một ghi chú. Sau khi các câu lệnh in trong hàm digests () của bạn, bạn cần xóa ít nhất là sha. Tôi không thể nói liệu bạn có nên xóa md5 hay không. Tôi sẽ chỉ sử dụng "del sha". Nếu bạn không, mọi tệp sau tệp đầu tiên sẽ có hàm băm không chính xác. Để chứng minh điều đó, tạo một thư mục tmp và sao chép một tập tin vào nó. Bây giờ tạo 2 bản sao của tệp đó và chạy tập lệnh của bạn. Bạn sẽ nhận được 3 băm khác nhau, đó không phải là điều bạn muốn. Chỉnh sửa: Tôi nghĩ rằng chức năng đã đọc qua một tập hợp các tệp, không chỉ đọc một tệp duy nhất tại một thời điểm ... Bỏ qua việc sử dụng này. ;)
Terry Wendt

1
@TerryWendt Bạn đã làm tôi lo lắng trong một giây. :) Có, digestschỉ xử lý một tệp duy nhất trên mỗi cuộc gọi. Vì vậy, ngay cả khi bạn đã gọi nó trong một vòng lặp, nó sẽ tạo ra bối cảnh md5 & sha mới cho mỗi cuộc gọi. FWIW, bạn có thể thưởng thức hàm băm SHA-256 có thể nối lại của tôi .
PM 2Ring

5

Bạn luôn có thể sử dụng một cái gì đó như GNU song song :

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

Ngoài ra, chỉ cần chạy một trong hai trong nền:

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

Hoặc, lưu đầu ra vào các tệp khác nhau và chạy nhiều công việc trong nền:

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

Điều đó sẽ khởi chạy nhiều md5sumvà nhiều sha256sumtrường hợp như bạn có tệp và tất cả chúng sẽ chạy song song, lưu kết quả đầu ra của chúng vào tên tệp tương ứng. Mặc dù cẩn thận, điều này có thể trở nên nặng nề nếu bạn có nhiều tập tin.


1
Xem bình luận cho Marco, lo lắng của tôi là mặc dù lệnh sẽ song song, đĩa chậm được truy cập hai lần cho cùng một dữ liệu.
Lekensteyn

Nhưng liệu sự tồn tại của bộ đệm đĩa có khiến bạn lo lắng không cần thiết?
Twinkles

2
@Twinkles Để trích dẫn Lekensteyn ở trên, "Vấn đề với cách tiếp cận đó là một lệnh có thể nhanh hơn lệnh kia, dẫn đến bộ đệm đĩa bị xóa và được nạp lại sau đó với cùng một dữ liệu."
Matt Nordhoff

2
@MattNordhoff Một điều nữa, một người lập lịch I / O thông minh nên chú ý và tối ưu hóa cho. Người ta có thể nghĩ: "Trình lập lịch I / O khó đến mức nào để đưa kịch bản này vào tài khoản?" Nhưng với đủ các kịch bản khác nhau mà bộ lập lịch I / O cần tính đến, nó đột nhiên trở thành một vấn đề khó khăn. Vì vậy, tôi đồng ý rằng người ta không nên cho rằng bộ nhớ đệm sẽ giải quyết vấn đề.
kasperd

1
Giả sử IO chậm hơn đáng kể so với bất kỳ công cụ nào có liên quan, cả hai công cụ nên được làm chậm lại với cùng tốc độ vì IO. Do đó, nếu một công cụ quản lý để có được ít khối dữ liệu hơn công cụ kia, thì công cụ kia sẽ nhanh chóng bắt kịp các tính toán sử dụng dữ liệu trong bộ đệm đĩa. Đó là lý thuyết, tôi rất muốn thấy một số kết quả thử nghiệm chứng minh điều đó thật
khó khăn

3

Out of tò mò liệu một kịch bản Python đa luồng sẽ làm giảm thời gian chạy, tôi tạo này digest.pykịch bản mà sử dụng threading.Thread, threading.Queuehashlibđể tính toán băm cho nhiều file.

Việc triển khai Python đa luồng thực sự nhanh hơn một chút so với sử dụng peevới coreutils. Mặt khác, Java là ... meh. Các kết quả có sẵn trong thông báo cam kết này :

Để so sánh, đối với tệp 2,3 GiB (min / avg / max / sd giây cho n = 10):

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

Đầu ra băm tương thích với đầu ra được sản xuất bởi coreutils. Vì độ dài phụ thuộc vào thuật toán băm, công cụ này không in nó. Cách sử dụng (để so sánh, peecũng đã được thêm vào):

$ ./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  -

Tôi sẽ đề nghị so sánh pee "openssl sha256" "openssl md5" < file, nhưng, thành thật mà nói, tôi chỉ thử nó và nó không đánh bại digest.py. Nó thu hẹp khoảng cách, mặc dù.
Matt Nordhoff

1

Jacksum là một tiện ích độc lập miễn phí và nền tảng để tính toán và xác minh tổng kiểm tra, CRC và băm (thông báo tiêu hóa) cũng như dấu thời gian của các tệp. (trích từ trang jacksum man )

Đó là nhận thức tệp lớn, nó có thể xử lý tệp lên tới 8 Exabyte (= 8.000.000.000 Gigabyte), giả định hệ điều hành của bạn tương ứng hệ thống tệp của bạn cũng nhận biết tệp lớn. (trích từ http://www.jonelo.de/java/jacksum/ )

Ví dụ sử dụng:

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

Đầu ra mẫu:

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

Trên Ubuntu, chạy lệnh apt-get install jacksumđể lấy nó.

Ngoài ra, mã nguồn có sẵn tại


Trong khi điều này không tạo ra tổng kiểm tra chính xác, chương trình Java này tính toán chậm gấp đôi so với coreutils. Xem tin nhắn cam kết này .
Lekensteyn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.