gzipped json 与高效二进制序列化的性能
Performance of gzipped json vs efficient binary serialization
JSON 和 Gzip 是一种序列化数据的简单方法。这些在编程语言中被广泛实现。此外,这种表示形式可以跨系统移植(是吗?)。
我的问题是,与非常高效的二进制序列化方法相比,json+gzip 是否足够好(成本低于 2 倍)?我在序列化各种数据时寻找 space 和时间成本。
使用 json+gzip 序列化比 rawbytes+gzip 多使用 25% space 用于数字和对象。对于精度有限的数字(4 位有效数字),序列化大小是相同的。似乎对于小规模应用程序,就数据大小而言,使用 json+gzip 就足够了。即使在发送记录数组时也是如此,其中每条记录都完整地拼出了字段和值(JavaScript 中存储数据的常用方式)。
以下实验的来源:https://github.com/csiz/gzip-json-performance
数字
我选择了一百万个浮点数(64 位)。我假设这些数字来自某些自然来源,所以我使用指数分布生成它们,然后将它们四舍五入为 4 位有效数字。因为 JSON 写下了整个表示,我认为存储大量数字可能会产生更大的成本(例如,存储 123456.000000 与 0.123456)所以我检查了这两种情况。我还检查未四舍五入的序列号。
在序列化小数字时,压缩 json 使用的大小比压缩二进制大 9%(数量级约为 1.0,因此只需写下几位数字):
json 3.29mb json/raw 43%
binary 3.03mb binary/raw 40%
json/binary 1.09
压缩后 json 使用的大小比序列化大数字时压缩二进制小 17%(数量级约为 1000000,需要写下更多数字):
json 2.58mb json/raw 34%
binary 3.10mb binary/raw 41%
json/binary 0.83
压缩后 json 使用的大小比序列化全精度双精度时压缩二进制文件大 22%:
json 8.90mb json/raw 117%
binary 7.27mb binary/raw 95%
json/binary 1.22
对象
对于对象,我在 JSON 中以通常的惰性方式对它们进行序列化。每个对象都存储为带有字段名称和值的完整记录。 "choice" 枚举的值已完整说明。
[
{
"small number": 0.1234,
"large number": 1234000,
"choice": "two"
},
...
]
为了高效的二进制表示,我将对象矢量化。我存储对象的数量,然后是小数字的连续向量,然后是选择枚举的连续向量。在这种情况下,我假设枚举值是已知的并且是固定的,所以我将索引存储到这个枚举中。
n = 1e6
small number = binary([0.1234, ...])
large number = binary([1234000, ...])
choice = binary([2, ...]) # indexes to the enum ["zero", "one", ..., "four"]
在存储对象时,压缩 json 使用的大小比压缩二进制大 27%:
json 8.36mb json/raw 44%
binary 6.59mb binary/raw 35%
json/binary 1.27
JSON 和 Gzip 是一种序列化数据的简单方法。这些在编程语言中被广泛实现。此外,这种表示形式可以跨系统移植(是吗?)。
我的问题是,与非常高效的二进制序列化方法相比,json+gzip 是否足够好(成本低于 2 倍)?我在序列化各种数据时寻找 space 和时间成本。
使用 json+gzip 序列化比 rawbytes+gzip 多使用 25% space 用于数字和对象。对于精度有限的数字(4 位有效数字),序列化大小是相同的。似乎对于小规模应用程序,就数据大小而言,使用 json+gzip 就足够了。即使在发送记录数组时也是如此,其中每条记录都完整地拼出了字段和值(JavaScript 中存储数据的常用方式)。
以下实验的来源:https://github.com/csiz/gzip-json-performance
数字
我选择了一百万个浮点数(64 位)。我假设这些数字来自某些自然来源,所以我使用指数分布生成它们,然后将它们四舍五入为 4 位有效数字。因为 JSON 写下了整个表示,我认为存储大量数字可能会产生更大的成本(例如,存储 123456.000000 与 0.123456)所以我检查了这两种情况。我还检查未四舍五入的序列号。
在序列化小数字时,压缩 json 使用的大小比压缩二进制大 9%(数量级约为 1.0,因此只需写下几位数字):
json 3.29mb json/raw 43%
binary 3.03mb binary/raw 40%
json/binary 1.09
压缩后 json 使用的大小比序列化大数字时压缩二进制小 17%(数量级约为 1000000,需要写下更多数字):
json 2.58mb json/raw 34%
binary 3.10mb binary/raw 41%
json/binary 0.83
压缩后 json 使用的大小比序列化全精度双精度时压缩二进制文件大 22%:
json 8.90mb json/raw 117%
binary 7.27mb binary/raw 95%
json/binary 1.22
对象
对于对象,我在 JSON 中以通常的惰性方式对它们进行序列化。每个对象都存储为带有字段名称和值的完整记录。 "choice" 枚举的值已完整说明。
[
{
"small number": 0.1234,
"large number": 1234000,
"choice": "two"
},
...
]
为了高效的二进制表示,我将对象矢量化。我存储对象的数量,然后是小数字的连续向量,然后是选择枚举的连续向量。在这种情况下,我假设枚举值是已知的并且是固定的,所以我将索引存储到这个枚举中。
n = 1e6
small number = binary([0.1234, ...])
large number = binary([1234000, ...])
choice = binary([2, ...]) # indexes to the enum ["zero", "one", ..., "four"]
在存储对象时,压缩 json 使用的大小比压缩二进制大 27%:
json 8.36mb json/raw 44%
binary 6.59mb binary/raw 35%
json/binary 1.27