在 python 中为大文件创建校验和的最快方法

Posted

技术标签:

【中文标题】在 python 中为大文件创建校验和的最快方法【英文标题】:the fastest way to create checksum for large files in python 【发布时间】:2010-12-04 16:48:00 【问题描述】:

我需要通过网络传输大文件,并且需要每小时为它们创建校验和。所以生成校验和的速度对我来说至关重要。

不知何故,我无法让 zlib.crc32 和 zlib.adler32 在 Windows XP Pro 64 位机器上处理大于 4GB 的文件。我怀疑我在这里达到了 32 位限制?使用 hashlib.md5 我可以得到一个结果,但问题是速度。为 4.8GB 文件生成一个 md5 大约需要 5 分钟。任务管理器显示进程只使用一个内核。

我的问题是:

    有没有办法让 crc 在大文件上工作?我更喜欢使用 crc 而不是 md5 如果没有,有没有办法加快 md5.hexdigest()/md5.digest?或者在这种情况下任何hashlib hexdigest/digest?也许将其拆分为多线程进程?我该怎么做?

PS:我正在开发类似于“资产管理”系统的东西,有点像 svn,但资产由大型压缩图像文件组成。这些文件有微小的增量更改。检测更改和错误检测需要散列/校验和。

【问题讨论】:

你有什么理由不能只使用 rsync 吗? 您是否需要检查它们的完整性(使用适当的算法,这是实际的问题)只是因为您通过网络传输文件?如果是这样,这已经在帧的硬件级别和 Tcp 层中针对任何缺失部分进行了验证(我在这里假设一个 Tcp 连接)。对不起,如果这听起来很明显,但我宁愿问。 大家好,感谢您的回复。为什么我不能使用 rsync,因为这几乎就像一个传输大型压缩图像文件的资产管理系统。几个人在处理一些文件。这些文件有微小的增量更改需要检测。因此我正在尝试使用校验和/哈希。 【参考方案1】:

这是算法选择问题,而不是库/语言选择问题!

似乎主要考虑两点:

磁盘 I/O 对整体性能的影响有多大? 错误检测功能的预期可靠性是多少?

显然,第二个问题的答案类似于“允许一些假阴性”,因为相对于 4Gb 消息,任何 32 位散列的可靠性,甚至在中等嘈杂的频道中,几乎不会是绝对的。

假设可以通过多线程改进 I/O,我们可以选择不需要对完整消息进行顺序扫描的哈希。相反,我们可以并行处理文件,对各个部分进行哈希处理,然后组合哈希值或附加它们,以形成更长、更可靠的错误检测设备。

下一步可能是将这种文件处理形式化为有序部分,并按原样传输它们(在接收者端重新粘合在一起)。这种方法以及有关文件生成方式的附加信息(例如,它们可以通过附加来专门修改,如日志文件),甚至可以限制所需的哈希计算量。这种方法增加的复杂性需要权衡快速 CRC 计算的愿望。

旁注:Alder32 限制在特定阈值以下的消息大小。这可能只是 zlib API 的限制。 (顺便说一句,我找到的关于 zlib.adler32 的参考资料使用了一个缓冲区,而且……在我们巨大的消息的上下文中应该避免这种方法,有利于流式处理:从文件中读取一点,计算,重复。 .)

【讨论】:

嗨 mjv,感谢您的回复。所以我想我应该在文件的几个部分上创建校验和并将它们组合起来? @pixelblender 是的,只要 I/O 不是瓶颈,一个多线程实现可以并行处理文件的 100 Mb 字节“切片”,可以预期是总体上比单线程方法更快。您需要进行试验以确定最佳线程数(总是会出现添加线程不会提高性能的点)。来自单个“切片”的 CRC 的有序列表可以是 CRC 本身,或者,最好可以附加 CRC 以形成更长的密钥,从而提供更好的错误检测。【参考方案2】:

首先,任何 CRC 算法都没有固有的东西可以阻止它们处理任意长度的数据(但是,特定的实现可能会施加限制)。

但是,在文件同步应用程序中,这可能无关紧要,因为您可能不想在文件变大时对整个文件进行哈希处理,而只是对块进行哈希处理。如果您对整个文件进行哈希处理,并且每一端的哈希值不同,则您必须复制整个文件。如果您散列固定大小的块,那么您只需复制散列已更改的块。如果对文件的大部分更改都是本地化的(例如数据库),那么这可能需要更少的复制(并且更容易将每个块的计算分散到多个核心)。

至于哈希算法本身,基本的权衡是速度与没有冲突(两个不同的数据块产生相同的哈希)。 CRC-32 速度很快,但只有 2^32 个唯一值,可能会出现冲突。 MD5 慢得多,但有 2^128 个唯一值,因此几乎不会出现碰撞(但理论上仍然是可能的)。较大的哈希值(SHA1,SHA256,...)具有更多唯一值,但速度仍然较慢:我怀疑您是否需要它们:您担心意外冲突,不像数字签名应用程序,您会故意担心(恶意)设计的碰撞。

听起来您正在尝试做一些与 rsync 实用程序非常相似的事情。你可以只使用 rsync 吗?

【讨论】:

嗨斯蒂芬,感谢您的回复。是的,碰撞对我来说不是问题,这就是我更喜欢使用 crc32 的原因。我已经编辑了关于我想用校验和完成什么的帖子。 即使您找不到合适的 CRC32 算法的 Python 实现,您也应该能够适应以任何语言发布的实现。您甚至可以利用 Python 的功能来链接到本机代码库。这甚至可能有助于提高速度(但您的性能可能会受到 CRC-32 磁盘 I/O 的限制)。 CRC 算法相当简单。我已经在几行 C 语言和一个静态数据表中实现了 CRC-8 和 CRC-16。我不记得实现了 CRC-32,但我很确定它不会复杂得多。【参考方案3】:

您可能会遇到 XP 中文件的大小限制。 64 位为您提供更多寻址空间(为每个应用程序移除 2GB(左右)的寻址空间),但可能对文件大小问题无济于事。

【讨论】:

【参考方案4】:

由于 MD5 的本质,您不可能使用多个核心来计算大文件的 MD5 哈希:它希望将消息分成块并以严格的顺序输入哈希函数。但是,您可以使用一个线程将文件读入内部队列,然后在单独的线程中计算哈希值。我不认为这会给您带来任何显着的性能提升。

处理一个大文件需要很长时间的事实可能是由于“无缓冲”读取。尝试一次读取 16 Kb,然后将内容以块的形式提供给散列函数。

【讨论】:

感谢安东的回复。我使用 f.read(1048576) 并为每次读取更新 haslib.md5() 。是的,我想创建另一个线程来计算哈希不会带来那么大的性能提升【参考方案5】:

md5 本身不能并行运行。但是,您可以分段(并行)对文件进行 md5,并获取哈希列表的 md5。

但是,假设哈希不受 IO 限制,我怀疑它是。正如 Anton Gogolev 所建议的那样 - 确保您正在有效地读取文件(以大的 2 次方块)。完成后,请确保文件没有碎片。

对于新项目,还应选择 sha256 等哈希而不是 md5。

对于 4Gb 文件,zlib 校验和是否比 md5 快得多?

【讨论】:

SHA256 会比 MD5 慢很多,没有必要。是的,有一个成功的攻击来设计与 MD5 的冲突,但这个应用程序并没有尝试加密安全。他使用哈希作为优化来防止不必要的复制。 感谢道格拉斯的回复。我认为 sha256 对我来说有点太多了,碰撞对我来说并不是一个真正的问题。【参考方案6】:

您尝试过crc-generator 模块吗?

【讨论】:

以上是关于在 python 中为大文件创建校验和的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

查找小数位数和的最快方法

在R中获取矩阵列的加权和的最快方法

从文本文件中读取数据并将其分配给数据框的最快方法是啥?

获取 GCS 中文件夹的文件数和总大小的最快方法?

使用以太网校验和的 esp32 OTA 失败

计算 CRC16 校验和的函数