You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从pyzstd迁移至Python内置zstd模块的压缩确定性差异问询

问题描述

我们正将压缩层从pyzstd迁移至Python 3.14引入的内置compression.zstd模块,迁移中发现一处行为差异:

  • 使用pyzstd.compress()调用时,多次执行总能生成完全相同的字节输出;
  • 使用内置zstd.compress()的等效调用时,相同输入连续两次调用生成的字节对象大小有时不同。

两次调用间会从磁盘重新加载同一.zst文件实例化ZstdDict,相关测试用例test_compress_after_reloading_dict_from_disk_produces_identical_output有时失败有时通过,具体代码如下:

pyzstd调用代码

pyzstd.compress(
    data=content,
    zstd_dict=training_dict.as_digested_dict
)

内置zstd调用代码

zstd.compress(
    data=content,
    zstd_dict=training_dict.as_digested_dict
)

字典加载与测试代码

input = {
  "test_1": 1283998000000,
  "test_2": 0,
  "test_3": "test"
}

CONTENT = json.dumps(input).encode('utf-8')

def _load_dict(path: str) -> zstd.ZstdDict:
    with open(path, "rb") as f:
        return zstd.ZstdDict(f.read())

def test_compress_after_reloading_dict_from_disk_produces_identical_output():
    training_dict = _load_dict(DICT_PATH)
    result_1 = zstd.compress(data=CONTENT, zstd_dict=training_dict.as_digested_dict)

    training_dict = _load_dict(DICT_PATH)
    result_2 = zstd.compress(data=CONTENT, zstd_dict=training_dict.as_digested_dict)

    assert result_1 == result_2, (
        f"Reloading ZstdDict from disk changed the compressed output.\n"
        f"  Before reload: {len(result_1)} bytes\n"
        f"  After reload:  {len(result_2)} bytes"
    )
原因分析

这个差异的核心原因在于内置zstd.ZstdDict的as_digested_dict属性在每次实例化字典时,可能生成带有不同动态元数据的消化字典,而pyzstd在处理字典时默认做了更严格的一致性保证,具体细节如下:

  • 内置zstd模块的ZstdDict在调用as_digested_dict时,会自动附加一些动态生成的元数据(如内部缓存标识、字典加载时的上下文标记等),这些元数据会被纳入压缩上下文的初始化流程。每次从磁盘重新加载字典并实例化ZstdDict时,这些动态元数据可能存在细微差异,导致压缩上下文的初始化状态不同,最终影响输出字节的大小。
  • pyzstd的compress方法在使用预训练字典时,默认会过滤掉这些非必要的动态元数据,仅保留字典的核心压缩逻辑部分,因此每次调用的压缩上下文完全一致,输出结果也完全相同。

此外,Zstd原生算法在部分优化策略下存在一定的非确定性,但pyzstd内部额外做了一致性兼容处理,而内置模块直接暴露了底层Zstd库的原生行为,未添加该兼容层,这也是导致差异的原因之一。

内容的提问来源于stack exchange,提问作者datahack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 06:44:51