Я явно не добавляю ничего принципиально нового, но добавил этот ответ, прежде чем приступил к комментированию статуса, плюс регионы кода проясняют ситуацию - во всяком случае, специально для ответа на вопрос @ Nemo из ответа Omnifarious:
Я немного подумал о контрольных суммах (пришел сюда в поисках предложений по размерам блоков, в частности), и обнаружил, что этот метод может быть быстрее, чем вы ожидаете. Взятие самого быстрого (но довольно типичного) timeit.timeit
или /usr/bin/time
результата каждого из нескольких методов проверки контрольной суммы файла ок. 11MB:
$ ./sum_methods.py
crc32_mmap(filename) 0.0241742134094
crc32_read(filename) 0.0219960212708
subprocess.check_output(['cksum', filename]) 0.0553209781647
md5sum_mmap(filename) 0.0286180973053
md5sum_read(filename) 0.0311000347137
subprocess.check_output(['md5sum', filename]) 0.0332629680634
$ time md5sum /tmp/test.data.300k
d3fe3d5d4c2460b5daacc30c6efbc77f /tmp/test.data.300k
real 0m0.043s
user 0m0.032s
sys 0m0.010s
$ stat -c '%s' /tmp/test.data.300k
11890400
Итак, похоже, что для Python и / usr / bin / md5sum требуется около 30 мс для файла размером 11 МБ. Соответствующая md5sum
функция ( md5sum_read
в приведенном выше списке) очень похожа на функцию Omnifarious:
import hashlib
def md5sum(filename, blocksize=65536):
hash = hashlib.md5()
with open(filename, "rb") as f:
for block in iter(lambda: f.read(blocksize), b""):
hash.update(block)
return hash.hexdigest()
Конечно, они из одиночных прогонов ( mmap
те, которые выполняются на несколько шагов быстрее, когда выполняется, по крайней мере, несколько десятков прогонов), и мой обычно получает дополнительный f.read(blocksize)
после того, как буфер исчерпан, но это достаточно повторяется и показывает, что md5sum
в командной строке не обязательно быстрее, чем реализация Python ...
РЕДАКТИРОВАТЬ: Извините за долгую задержку, не смотрел на это некоторое время, но чтобы ответить на вопрос @ EdRandall, я запишу реализацию Adler32. Тем не менее, я не проводил тесты для этого. По сути, это то же самое, что и CRC32: вместо вызовов init, update и digest все является zlib.adler32()
вызовом:
import zlib
def adler32sum(filename, blocksize=65536):
checksum = zlib.adler32("")
with open(filename, "rb") as f:
for block in iter(lambda: f.read(blocksize), b""):
checksum = zlib.adler32(block, checksum)
return checksum & 0xffffffff
Обратите внимание, что это должно начинаться с пустой строки, так как суммы Адлера действительно различаются, когда начинаются с нуля, в сравнении с их суммой ""
, то есть 1
- 0
вместо этого можно начать с CRC . AND
-Ную требуется , чтобы сделать это 32-разрядное целое число без знака, который гарантирует , что он возвращает то же значение между версиями Python.
md5sum
?