为什么python hashlib.md5比linux coreutils md5sum快
我刚发现,使用Python的hashlib.md5可能比coreutils的md5sum要快。
这是关于python hashlib的内容:
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]
我做了一个测试,结果有4列,分别是计算md5和sha1所花的时间。
第一列是coreutils的md5sum或sha1sum的计算时间。
第二列是使用python hashlib的md5或sha1,读取1048576字节时的计算时间。
第三列是使用python hashlib的md5或sha1,读取32768字节时的计算时间。
第四列是使用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。但这似乎是错误的。
2 个回答
我不太确定你是怎么测量时间的,但这个时间差可能是因为你每次调用 shell_hash
时,启动一个子进程所花的时间(还有 shlex.split
的解析时间)造成的。
coreutils有自己的C语言实现,而Python则是通过调用libcrypto来处理,这里面还涉及到一些特定架构的汇编实现。对于sha1来说,这个差别更大。
不过在coreutils-8.22版本中,这个问题已经得到修复(当配置为--with-openssl时),而且在一些新版本的操作系统中,比如Fedora 21、RHEL 7和Arch等,已经启用了这个功能。
虽然在某些系统上,调用这个命令的速度目前比较慢,但从长远来看,这种做法更好,因为可以利用这些独立命令中封装的所有逻辑,而不是重新实现一遍。例如,在coreutils中,正在支持更好的稀疏文件读取,这样就不会重复从内核读取零值数据。如果可能的话,最好能够透明地利用这些功能。