ensure_ascii=False 实测:中文越多越快,纯中文快 35%,体积小 1.81 倍

举报
yd_232353574 发表于 2026/11/06 08:23:10 2026/11/06
【摘要】 实测 5000 条数据:ensure_ascii=False 让纯中文数据小 1.81 倍,汉字多时反而快 35%,没有汉字时略慢几个百分点。附两种写法 MD5 不同、gzip 后体积反转这两个副作用。

存 JSON 时体积大一倍

有个接口返回的中文很多,存盘之后文件比预期大不少。我一开始以为是数据本身多了,检查了几遍源数据,没多。

后来把同一份数据用两种方式序列化,对比文件大小,找到了原因。

体积:差多少

我造了 5000 条记录,每条含中文字段、英文邮箱、标签数组、布尔值和数字。

用不同参数序列化,文件的字节数:

  • 默认(ensure_ascii=True)→ 1675563 字节
  • ensure_ascii=False → 1180563 字节,少 29.5%
  • separators=(',', ':') 紧凑 → 1595564 字节,比默认少 4.8%
  • ensure_ascii=False 加紧凑 → 1100564 字节,比默认少 34.3%
  • indent=2 → 1965565 字节,比默认多 17.3%
  • ensure_ascii=False 加 indent=2 → 1470565 字节

纯中文的场景差距更大。我单独测了 5000 条只有中文的记录:

  • ensure_ascii=True → 3613890 字节
  • ensure_ascii=False → 1993890 字节

1.81 倍。

为什么差这么多

ensure_ascii=True(默认值)会把所有非 ASCII 字符转成 \uXXXX 形式。一个中文字符变成 6 个 ASCII 字符(反斜杠、u 加四位十六进制),UTF-8 下则是 3 个字节。

实测一个字的差别就够说明:写 {"k": "中"},默认写法输出 {"k": "\u4e2d"},前者 15 字节,后者 12 字节,差 3 字节,正好是一个汉字的 UTF-8 长度。

速度:方向取决于中文占比

这部分我一开始测错了,值得单独拎出来说。

第一次测的时候,我把默认写法排在第一个,测出 ensure_ascii=False 慢了 21%。后来发现是测量方法的问题:排在第一个的写法会吃掉一次性的预热开销(代码路径首次进入、内存分配)。加了预热,再把各写法交错跑 15 轮取中位数,结论反了过来。

三档中文占比下各跑 15 轮,取中位数:

  • 纯 ASCII,一个汉字都没有 → 默认 8.10 ms,ensure_ascii=False 8.88 ms,慢 9.7%,两边体积完全一样
  • 混合,中文字段占一部分 → 默认 12.76 ms,ensure_ascii=False 12.42 ms,持平,体积差 1.42 倍
  • 纯中文 → 默认 18.62 ms,ensure_ascii=False 12.07 ms,快 35.2%,体积差 1.81 倍

规律很清楚:汉字越多,ensure_ascii=False 越快;一个汉字都没有时,它略慢几个百分点。

原因也不绕。转义时每个汉字要展开成 6 个 ASCII 字符,纯中文场景输出量直接翻倍,编码开销跟着涨;ensure_ascii=False 直接输出 UTF-8 字节,几乎是原样拷贝。反过来,数据里一个汉字都没有时,转义没有任何成本,ensure_ascii=False 反而多走一次编码。

同一批混合数据上,紧凑分隔符和缩进的影响也在:ensure_ascii=False 配紧凑分隔符最快,12.03 ms,比默认快 11.9%;indent=2 比默认慢 7.2%;ensure_ascii=False 配 indent=2 慢 15.8%。带缩进的 JSON 是给人看的,机器读的场景别加。

一个容易被忽略的副作用:文件内容变了

这点比体积更值得注意。我把两种方式写出的文件算了 MD5:

  • ascii.json → 04d49eb2480a5ee16b911e57a765f518
  • nonascii.json → 268c4c5589672347a2ea3b798affd072

同一份数据,两个不同的 MD5。

如果你的系统里有任何依赖文件内容做键的地方——ETag、内容寻址的存储、去重哈希、缓存键——切换 ensure_ascii 就等于把这些键全部换掉。数据库里存的文件哈希、对象存储里的对象键,都会变。

已经入库的历史数据和新数据混在一起时,对不上是必然的。

压缩之后会怎样

我原以为压缩能把差距抹平,实测发现方向相反。同一份混合数据做 gzip 压缩之后:

  • 默认写法 → 44941 字节
  • ensure_ascii=False → 51796 字节

\uXXXX 形式全是重复的 ASCII 字符,很好压缩;原始 UTF-8 汉字的字节分布更散,压缩后反而更大。所以「关掉转义再开压缩」不一定更省流量,中文占比高时这个组合要自己实测。

到底用哪个

分场景:

  • 日志和调试输出 → ensure_ascii=False。中文直接可读,排障时不用手动转义回去。
  • 接口返回 → ensure_ascii=False,但要确保响应头写明 Content-Type: application/json; charset=utf-8。有些老客户端会用 ISO-8859-1 解析,那就会变成乱码。
  • 内容寻址、算哈希 → 想清楚切换的代价。同一份数据两种写法哈希不同,混用会出事。
  • 机器间传输 → 体积比可读性重要,用 ensure_ascii=False 加 separators=(',', ':'),再走 gzip;中文占比低时压缩收益要重新实测。

一句话

ensure_ascii=True 让中文变成 \uXXXX,纯中文场景体积差 1.81 倍;ensure_ascii=False 在汉字多的时候快 35%,一个汉字都没有时略慢几个百分点。它的收益是体积和可读性,代价是文件 MD5 会变,依赖内容哈希的地方要留意。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。