5

私の現在のアプローチはこれです:

def get_hash(path=PATH, hash_type='md5'):
    func = getattr(hashlib, hash_type)()
    with open(path, 'rb') as f:
         for block in iter(lambda: f.read(1024*func.block_size, b''):
             func.update(block)
    return func.hexdigest()

i5 @ 1.7 GHz で 842MB の iso ファイルの md5sum を計算するには、約 3.5 秒かかります。ファイルを読み取るさまざまな方法を試しましたが、いずれも結果が遅くなります。おそらく、より速い解決策はありますか?

編集: hashlib でサポートされているほとんどのハッシュ関数のデフォルトは(「sha384」と「sha512」を除く - それらの場合、デフォルトは) であるため、 2**16(内のf.read()) をに置き換えました。したがって、ブロック サイズは同じ (65536 ビット) のままです。1024*func.block_sizeblock_size64block_size128

EDIT(2): 何か間違ったことをしました。3.5 秒ではなく 8.4 秒かかります。:(

EDIT(3): 関数を再度実行したとき、どうやら Windows は +80% でディスクを使用していたようです。実に3.5秒かかります。ふぅ。

別の解決策 (~-0.5 秒、わずかに速い) は、os.open() を使用することです。

def get_hash(path=PATH, hash_type='md5'):
    func = getattr(hashlib, hash_type)()
    f = os.open(path, (os.O_RDWR | os.O_BINARY))
    for block in iter(lambda: os.read(f, 2048*func.block_size), b''):
        func.update(block)
    os.close(f)
    return func.hexdigest()

これらの結果は最終的なものではないことに注意してください。

4

1 に答える 1

3

md5openssl ツールで 2 秒かかる 874 MiB のランダム データ ファイルを使用すると、次のように速度を向上させることができました。

  • 最初の方法を使用すると、21 秒かかりました。
  • ファイル全体 (21 秒) をバッファーに読み取ってから、更新に 2 秒かかりました。
  • 次の関数をバッファ サイズ 8096 で使用すると、17 秒かかりました。
  • 次の関数をバッファ サイズ 32767 で使用すると、11 秒かかりました。
  • 次の関数をバッファ サイズ 65536 で使用すると、8 秒かかりました。
  • 次の関数をバッファ サイズ 131072 で使用すると、8 秒かかりました。
  • 次の関数をバッファ サイズ 1048576 で使用すると、12 秒かかりました。
def md5_speedcheck(path, size):
    pts = time.process_time()
    ats = time.time()
    m = hashlib.md5()
    with open(path, 'rb') as f:
        b = f.read(size)
        while len(b) > 0:
            m.update(b)
            b = f.read(size)
    print("{0:.3f} s".format(time.process_time() - pts))
    print("{0:.3f} s".format(time.time() - ats))

人間の時間は、私が上で述べたものです。これらすべてのプロセッサ時間はほぼ同じですが、違いは IO ブロッキングにあります。

ここでの重要な決定要因は、ディスクの待ち時間を軽減するのに十分な大きさのバッファー サイズを持つことですが、VM のページ スワップを回避するのに十分な大きさにすることです。私の特定のマシンでは、64 KiB が最適なようです。

于 2014-05-09T17:19:57.310 に答える