6

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

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

我的问题是:

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

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

4

6 回答 6

5

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

似乎主要有两点需要考虑:

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

显然,第二个问题的答案类似于“允许一些假阴性”,因为任何32 位散列的可靠性,相对于 4Gb 消息,即使在中等噪声的通道中,实际上也不是绝对的。

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

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

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

于 2009-10-07T17:24:08.143 回答
3

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

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

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

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

于 2009-10-07T18:02:08.270 回答
2

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

于 2009-10-08T23:02:25.297 回答
1

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

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

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

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

于 2009-10-07T16:39:25.690 回答
1

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

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

于 2009-10-07T16:36:30.360 回答
0

您是否尝试过crc-generator模块?

于 2009-10-07T16:43:18.837 回答