【问题标题】:How to compute several hashes at the same time?如何同时计算多个哈希?
【发布时间】:2020-07-15 21:02:57
【问题描述】:

我想计算同一个文件的多个哈希值并通过多处理来节省时间。

据我所见,从 ssd 读取文件相对较快,但哈希计算几乎慢了 4 倍。如果我想计算 2 个不同的哈希值(md5 和 sha),它会慢 8 倍。我希望能够在不同的处理器内核上并行计算不同的哈希值(最多 4 个,具体取决于设置),但不明白如何绕过 GIL。

这是我当前的代码 (hash.py):

import hashlib
from io import DEFAULT_BUFFER_SIZE

file = 'test/file.mov' #50MG file

def hash_md5(file):
    md5 = hashlib.md5()
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            md5.update(chunk)
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return md5.hexdigest()

def hash_sha(file):
    sha = hashlib.sha1()
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            sha.update(chunk)
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return sha.hexdigest()

def hash_md5_sha(file):
    md5 = hashlib.md5()
    sha = hashlib.sha1()
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            md5.update(chunk)
            sha.update(chunk)
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return md5.hexdigest(), sha.hexdigest()

def read_file(file):
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return

我做了一些测试,结果如下:

from hash import *
from timeit import timeit
timeit(stmt='read_file(file)',globals=globals(),number = 100)
1.6323043460000122
>>> timeit(stmt='hash_md5(file)',globals=globals(),number = 100)
8.137973076999998
>>> timeit(stmt='hash_sha(file)',globals=globals(),number = 100)
7.1260356809999905
>>> timeit(stmt='hash_md5_sha(file)',globals=globals(),number = 100)
13.740918666999988

这个结果应该是一个函数,主脚本将遍历文件列表,并且应该检查不同文件的不同哈希值(从 1 到 4)。 有什么想法可以实现吗?

【问题讨论】:

  • 您可以使用concurrent.futures 类中的PoolProcessExecutor() 方法。我相信这会帮助你实现你想要的。您可以在此处找到该库的更多详细信息:concurrent.futures

标签: python multithreading hash md5 sha


【解决方案1】:

正如 cmets 中的某人所说,您可以使用 concurrent.futures。我做了一些基准测试,最有效的方法是使用ProcessPoolExecutor。这是一个例子:

executor = ProcessPoolExecutor(4)
executor.map(hash_function, files)
executor.shutdown()

如果你想看看我的基准测试,你可以找到它们here 和结果:

Total using read_file: 10.121980099997018
Total using hash_md5_sha: 40.49621040000693
Total (multi-thread) using read_file: 6.246223400000417
Total (multi-thread) using hash_md5_sha: 19.588415799999893
Total (multi-core) using read_file: 4.099713300000076
Total (multi-core) using hash_md5_sha: 14.448464199999762

我使用了 40 个 300 MiB 的文件进行测试。

【讨论】:

  • 感谢您的回复和代码示例。我对 SSD 的结果看起来很有希望,但在慢速媒体上的相同测试实际上更慢:我猜这里的问题是外部 HDD 上的随机访问导致平均读取速度降低。有没有办法执行顺序读取但并行哈希计算?我的结果:pastebin.com/b6Cfiyp5
  • 据我所知,哈希算法通常不会以并行方式计算。您可以尝试使用更快的散列库(据我所知,hashlib 非常慢),也许还有一个承诺异步操作的文件 I/O 库。你可以在这里找到一个例子:aiofile,但我没有测试它。
  • 我知道单个哈希的计算不应该从并行处理中受益,但是同时多个哈希不是问题,对吧?我最初的想法是在 2 个不同的线程(或更多线程,如果需要更多哈希)中同时计算 sha 和 md5 哈希,但我不明白如何实现它。我想我需要使用多处理模块启动 2 个(或更多)python 进程并以某种方式与它们交换数据?或者为此特定目的创建一个 C 库并将其绑定到 python?
猜你喜欢
  • 2018-04-17
  • 2016-06-23
  • 2021-06-19
  • 2019-05-31
  • 2012-06-15
  • 2017-02-04
  • 2012-04-14
  • 2014-01-14
  • 1970-01-01
相关资源
最近更新 更多