为什么python hashlib.md5比linux coreutils md5sum快

为什么python hashlib.md5比linux coreutils md5sum快,python,md5,Python,Md5,我刚刚发现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

我刚刚发现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的校准时间,读取1048576chunk

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.)
第3列是python hashlib md5或sha1的校准时间,读取32768chunk

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.)
第四列是python hashlib md5或sha1的校准时间,通过读取512chunk

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(RFC1321)的实现

在gnulib中,32768读取的md5块

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


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

我不确定您是如何对其进行计时的,但这种差异可能是因为您每次调用
shell\u hash
时花在旋转子进程上的时间(考虑
shlex.split
的解析时间)我不确定您是如何对其进行计时的,但这种差异很可能是因为每次调用
shell\u hash
时,您都需要花费大量时间来旋转一个子进程(同时考虑
shlex.split
的解析时间),而coreutils有自己的C实现,而python则使用特定于体系结构的汇编实现调用libcrypto。sha1的差异更大。 现在,这已经在coreutils-8.22中得到了修复(配置时使用openssl),并在较新的distos中启用,如Fedora 21、RHEL 7和Arch等


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

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


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

那里有很多移动部件。您可能正在测量第二个函数中的
POpen.communication
的性能。尝试在native bash中使用
time
对其计时。答案不太完整:不同实现之间通常会有性能差异,因此您不会期望Python和核心UTIL的速度一定相同。但是,您的方法中缺少一些东西,例如是否首先预热缓存,以及结果的差异是什么。至于代码,只需使用
[“md5sum”,path]
而不是
shlex.split('md5sum%s'%path)
,因为
shlex.split()
'%s%s'(x,y)
充其量只是做相反的事情。最坏的情况是,
shlex.split()
正在破坏参数。谢谢。我已经删除了
shlex
。我没想到Python和coreutils会以同样的速度实现md5。我会阅读代码来找出原因。那里有很多活动部件。您可能正在测量第二个函数中的
POpen.communication
的性能。尝试在native bash中使用
time
对其计时。答案不太完整:不同实现之间通常会有性能差异,因此您不会期望Python和核心UTIL的速度一定相同。但是,您的方法中缺少一些东西,例如是否首先预热缓存,以及结果的差异是什么。至于代码,只需使用
[“md5sum”,path]
而不是
shlex.split('md5sum%s'%path)
,因为
shlex.split()
'%s%s'(x,y)
充其量只是做相反的事情。最坏的情况是,
shlex.split()
正在破坏参数。谢谢。我已经删除了
shlex
。我没想到Python和coreutils会以同样的速度实现md5。我将阅读代码,找出为什么在缓存中启动进程需要0.400毫秒?“我希望不是。”迪特里切普——你的400毫秒跑哪儿去了?我甚至不确定OP在表中报告的单位是什么…时间单位是秒。我将使用
time md5sum
再次测试。400毫秒在缓存中启动进程?“我希望不是。”迪特里切普——你的400毫秒跑哪儿去了?我甚至不确定OP在表中报告的单位是什么…时间单位是秒。我将使用
time md5sum
再次测试。