ensure_ascii=False 实测:中文越多越快,纯中文快 35%,体积小 1.81 倍
存 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=False8.88 ms,慢 9.7%,两边体积完全一样 - 混合,中文字段占一部分 → 默认 12.76 ms,
ensure_ascii=False12.42 ms,持平,体积差 1.42 倍 - 纯中文 → 默认 18.62 ms,
ensure_ascii=False12.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→04d49eb2480a5ee16b911e57a765f518nonascii.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 会变,依赖内容哈希的地方要留意。
- 点赞
- 收藏
- 关注作者
评论(0)