【问题标题】:Why python hashlib.md5 is faster than linux coreutils md5sum为什么 python hashlib.md5 比 linux coreutils md5sum 快
【发布时间】:2014-03-25 03:04:04
【问题描述】:

我刚刚发现 python hashlib.md5 可能比 coreutils md5sum 快。

python 哈希库

def get_hash(fpath, algorithm='md5', block=32768):
    if not hasattr(hashlib, algorithm):
        return ''
    m = getattr(hashlib, algorithm)()
    if not os.path.isfile(fpath):
        return ''
    with open(fpath, 'r') as f:
        while True:
            data = f.read(block)
            if not data:
                break
            m.update(data)
    return m.hexdigest()

coreutils md5sum

def shell_hash(fpath, method='md5sum'):
    if not os.path.isfile(fpath):
        return ''
    cmd = [method, fpath] #delete shlex
    p = Popen(cmd, stdout=PIPE)
    output, _ = p.communicate()
    if p.returncode:
        return ''
    output = output.split()
    return output[0]

关于我计算 md5 和 sha1 的测试结果时间有 4 列。

第 1 列是 coreutils md5sum 或 sha1sum 的计算时间。

第 2 列是 python hashlib md5 或 sha1 的校准时间,通过读取 1048576 块。

第 3 列是 python hashlib md5 或 sha1 的校准时间,通过读取 32768 块。

第 4 列是 python hashlib md5 或 sha1 的校准时间,通过读取 512 块。

4.08805298805 3.81827783585 3.72585606575 5.72505903244
6.28456497192 3.69725108147 3.59885907173 5.69266486168
4.08003306389 3.82310700417 3.74562311172 5.74706888199
6.25473690033 3.70099711418 3.60972714424 5.70108985901
4.07995700836 3.83335709572 3.74854302406 5.74988412857
6.26068210602 3.72050404549 3.60864400864 5.69080018997
4.08979201317 3.83872914314 3.75350999832 5.79242300987
6.28977203369 3.69586396217 3.60469412804 5.68853116035
4.0824379921 3.83340883255 3.74298214912 5.73846316338
6.27566385269 3.6986720562 3.6079480648 5.68188500404
4.10092496872 3.82357311249 3.73044300079 5.7778570652
6.25675201416 3.78636980057 3.62911510468 5.71392583847
4.09579920769 3.83730792999 3.73345088959 5.73320293427
6.26580905914 3.69428491592 3.61320495605 5.69155502319
4.09030103683 3.82516098022 3.73244214058 5.72749185562
6.26151800156 3.6951239109 3.60320997238 5.70400810242
4.07977604866 3.81951498985 3.73287010193 5.73037815094
6.26691818237 3.72077894211 3.60203289986 5.71795105934
4.08536100388 3.83897590637 3.73681998253 5.73614501953
6.2943251133 3.72131896019 3.61498594284 5.69963502884
(My computer has 4-core i3-2120 CPU @ 3.30GHz, 4G memory. 
 The file calculated by these program is about 2G in size.
 The odd rows are about md5 and the even rows are about sha1.
 The time in this table are in second.)

经过 100 多次测试,我发现 python hashlib 总是比 md5sum 或 sha1sum 快。

我还阅读了一些关于 Python2.7/Modules/{md5.c,md5.h,md5module.c} 和 gnulib lib/{md5.c,md5.h} 的源代码文档。它们都是 MD5 (RFC 1321) 的实现。

在 gnulib 中,md5 块被 32768 读取。

我对 md5 和 C 源代码了解不多。有人可以帮我解释一下这些结果吗?

我想问这个问题的另一个原因是许多人认为 md5sum 比 python_hashlib 快是理所当然的,他们更喜欢在编写 python 代码时使用 md5sum。但这似乎是错误的。

【问题讨论】:

  • 那里有很多活动部件。您可能正在第二个函数中测量POpen.communicate 的性能。尝试使用 time 在本机 bash 中计时。
  • 不是一个完整的答案:不同的实现之间通常会有性能差异,因此您不会期望 Python 和 Core Utils 的速度必然相同。但是,您的方法中缺少一些东西,例如您是否先预热缓存,以及结果的方差是多少。至于代码,只需使用["md5sum", path] 而不是shlex.split('md5sum %s' % path),因为shlex.split()'%s %s' % (x, y) 充其量只是在做相反的事情。在最坏的情况下,shlex.split() 正在破坏论点。
  • 谢谢。我已经删除了shlex。没想到 Python 和 coreutils 以同样的速度实现 md5。我会阅读代码找出原因。

标签: python md5


【解决方案1】:

coreutils 有它自己的 C 实现,而 python 使用特定于体系结构的程序集实现调用 libcrypto。 sha1 的差异甚至更大。 现在,这已在 coreutils-8.22 中修复(当配置 --with-openssl 时),并在 Fedora 21、RHEL 7 和 Arch 等较新的 disto 中启用。

请注意,尽管当前在某些系统上速度较慢,但​​调用命令是一种更好的长期策略,因为可以利用封装在单独命令中的所有逻辑,而不是重新实现。例如,在 coreutils 中,有待改进的稀疏文件读取支持,这样就不会从内核等冗余读取零。如果可能的话,最好透明地利用它。

【讨论】:

    【解决方案2】:

    我不确定您到底是如何计时的,但差异可能是因为您每次调用 @ 时都花时间启动子进程(还要考虑 shlex.split 的解析时间) 987654322@.

    【讨论】:

    • 400 毫秒在缓存中启动一个进程?我希望不会。
    • @DietrichEpp -- 你在哪里得到 400 毫秒?我什至不确定 OP 在该表中报告了哪些单位...
    • 时间单位是秒。我将使用time md5sum 再次测试。
    猜你喜欢
    • 2013-09-09
    • 2014-06-19
    • 2020-05-14
    • 2011-12-25
    • 2017-01-11
    • 1970-01-01
    • 2019-11-02
    • 2015-07-24
    相关资源
    最近更新 更多