Python xxHash 模块

2024 年 8 月 29 日 | 阅读 6 分钟

xxhash 是一个用于 Yann Collet 的 xxHash 库的 Python 模块。

xxHash 是一种极快的哈希计算,运行速度接近内存速度极限。它有效地通过了 SMHasher 测试套件,该套件评估哈希能力的性能、分布和不规则性特征。代码高度可移植,并且所有平台上的哈希值都相同(几乎没有大小端差异)。

处理大量数据只是问题的一部分。哈希在诸如哈希表和布隆过滤器等结构中也很有用。在这些用例中,哈希大量小数据(从几个字节开始)是很常见的。计算在这种场景下的性能可能完全不同,因为计算的某些部分,例如初始化或最终化,会产生固定成本。分支预测失误的影响也变得更加显著。

XXH3 专为处理长短数据源的卓越性能而设计。

质量

速度并不是唯一重要的属性。生成的哈希值应具有出色的分布和随机性,以便其任何子段都可用于分散表或索引,并根据生日悖论将冲突的可能性降至理论上的最小值。

xxHash 已通过 Austin Appleby 出色的 SMHasher 测试套件进行了测试,并通过了所有测试,确保了合理的质量水平。它还通过了 SMHasher 的较新分支的扩展测试,包括额外的场景和条件。

最后,xxHash 提供了其巨大的冲突分析器,能够生成和比较数十亿个哈希值,以测试 64 位哈希计算的极限。在这方面,xxHash 取得了遵循生日悖论的优异成绩。

构建修饰符

以下宏可以在构建时设置,以修改 libxxhash 的行为。默认情况下,它们通常处于禁用状态。

  1. XXH_INLINE_ALL:将所有函数内联,实现直接包含在 xxhash.h 中。内联函数对小键速度有益。当键长度在编译时表示为常量时,它非常有效,性能提升可达 200% 以上。
  2. XXH_PRIVATE_API:与 XXH_INLINE_ALL 结果相同。仍可用于向后兼容。该名称强调 XXH_* 符号不会被导出。
  3. XXH_NAMESPACE:将所有符号加上 XXH_NAMESPACE 的值作为前缀。此宏可以使用可编译的字符集。当 xxHash 的源代码被多次包含时,有助于避免符号命名冲突。用户应用程序使用常规函数名称,因为符号会自动通过 xxhash.h 进行解析。
  4. XXH_FORCE_MEMORY_ACCESS:默认策略 0 使用标准的 memcpy() 函数。策略 1 使用 gcc 特有的 packed 属性,可以更好地针对某些目标进行优化。策略 2 强制进行非对齐读取,这不符合标准;但有时可能是提取更好读取性能的唯一方法。策略 3 使用字节移位操作,这对于不内联 memcpy() 或没有字节交换指令的大端系统等旧编译器最有效。
  5. XXH_FORCE_ALIGN_CHECK:当输入对齐时,使用更快的直接读取路径。此选项可以提高输入哈希值已在 64 位或 32 位边界对齐时的主观性能,前提是正在运行的系统无法从非对齐地址加载内存或会遇到性能损失。在具有良好非对齐内存访问性能的平台上(对齐和非对齐访问使用相同的指令)会(略微)降低性能。此选项在 x64、x84 和 aarch64 上默认禁用,在所有其他平台上启用。
  6. XXH_VECTOR:手动选择一个向量指令集(默认:在编译时自动选择)。可用的指令集有 XXH_VSX、XXH_SSE、XXH_SCALAR、XXH_AVX2、XXH_NEON、XXH 和 AVX512。编译器可能需要额外的标志来确保正确支持(例如,Linux 上的 gcc 需要 -mavx2 用于 AVX3,-mavx512f 用于 AVX512)。
  7. XXH_NO_PREFETCH:禁用预取。某些平台或场景在没有预取的情况下性能可能更好。仅适用于 XXH3。
  8. 仅适用于 XXH3。XXH_PREFETCH_DIST:选择预取的距离。用于针对特定硬件平台的裸金属转换。
  9. XXH_NO_STREAM:禁用流式 API,仅限于单次调用变体。
  10. XXH_SIZE_OPT:0:默认,为速度优化。1:-Os 和 -Oz 的默认值:禁用一些用于大小优化的速度技巧。2:使代码尽可能小,性能可能会下降。
  11. XXH_NO_INLINE_HINTS:默认情况下,xxHash 使用 __attribute__((always_inline)) 和 __forceinline 来提高性能,但会增加代码大小。将此宏定义为 1 将所有内部函数声明为 static,允许编译器自行决定是否内联函数。这对于优化最小二进制尺寸非常有用,并且在 Clang 和 GCC 上使用 -Os、-O0、-fno 或 -Oz-inline 进行编译时会自动定义。根据编译器和架构,这也可能提高性能。
  12. XXH32_ENDJMP:用单个跳转替换 XXH32 的多分支最终化阶段。这对于性能来说是不可取的,尤其是在哈希不同大小的输入时。但是,根据具体的体系结构和编译器,对于小输入,跳转可能会提供略微更好的性能。默认禁用。
  13. XXH_NO_STDLIB:禁用对 函数的调用,特别是 malloc() 和 free()。libxxhash 的 XXH*_createState() 将始终失败并返回 NULL。但是,单次哈希(如 XXH32())或使用静态分配状态的流式处理可以正常工作。此构建标志对于没有动态分配的嵌入式环境很有用。
  14. XXH_STATIC_LINKING_ONLY:提供对内部状态声明的访问,用于静态链接。与动态链接相反,因为存在 ABI 更改的风险。
  15. XXH_NO_XXH3:从生成的二进制文件中移除与 XXH3(64 位和 128 位)相关的符号。有助于减小二进制文件大小,对于不使用 XXH3 的应用程序可以静默处理。
  16. XXH_NO_LONG_LONG:移除依赖于 64 位类型(XXH3 和 XXH64)的计算。仅会编译 XXH32。对于不支持 64 位类型的目标(模型和编译器)很有用。
  17. XXH_IMPORT:MSVC 特定:仅应为动态链接定义,因为它可防止链接错误。
  18. XXH_CPU_LITTLE_ENDIAN:默认情况下,通过编译时确定的运行时测试来确定。如果由于某种原因编译器无法执行运行时测试,可能会影响性能。可以通过将此宏设置为 1 来跳过自动检测并声明系统是小端序。设置为 0 表示大端序。
  19. XXH_DEBUGLEVEL:当设置为任何大于等于 1 的值时,会启用 assert() 语句。这会(略微)降低性能,但在调试会话中可能有助于查找错误。

安装

从源代码安装

前提条件

在 Debian/Ubuntu 上

在 CentOS/Fedora 上

用途

可以使用模块属性 VERSION 和 XXHASH_VERSION 分别获取模块版本及其后端 xxHash 库版本。

此模块与 hashlib 兼容,这意味着您可以像使用 hashlib.md5 一样使用它。

  1. update() 函数 - 使用额外字符串更新当前摘要
  2. intdigest() 函数 - 以整数形式返回当前摘要
  3. digest() 函数 - 返回当前摘要的值
  4. hexdigest() 函数 - 以十六进制数字字符串的形式返回当前摘要
  5. duplicate() 函数 - 返回当前 xxhash 对象的副本
  6. reset() 函数 - 重置状态

md5 digest 返回字节,但原始的 xxh64 和 xxh32 C API 返回整数。虽然此特定模块是 hashlib 兼容的,但还提供了 intdigest() 以获取整数摘要。

此模块提供的哈希算法的构造函数是 xxh64() 和 xxh32()。

例如,要获取字节字符串 b'Nobody assesses the spammish reiteration' 的摘要