【问题标题】:Is there a Javascript object notation format leaner than JSON/BSON?是否有比 JSON/BSON 更精简的 Javascript 对象表示法格式?
【发布时间】:2013-04-24 05:20:38
【问题描述】:

对于简单的 Javascript 对象树,是否有任何好的序列化/反序列化格式,其占用空间比 JSON 小得多? BSON 不是很令人印象深刻。

JSON 中的冗余开销对于许多对象共享同一组属性的树来说尤其重要。理论上,应该可以检测对象数组中的模式,从而不重复属性名称。

【问题讨论】:

  • 你试过压缩你的 JSON 吗?
  • @alex - 由于数据不可缓存,它会占用大量服务器 CPU。我宁愿首先生成一个紧凑的表示。
  • @PatriciaBrothers 通常,gzip 压缩已编译 lib 的序列化比在脚本中构建替代序列化要快得多。
  • 尝试使用protobuf prototypejs.org,它看起来有些难看,但是一旦你学会了如何使用它,你就会看到它的好处,它可以在最常用的语言服务器端2中运行

标签: javascript json bson


【解决方案1】:

您可以将 JSON 转换为更多的“数据库”格式,然后将其转换回常规对象。结果有时是值得的。

// Typed on the fly
var dict = [
  ["FirstName", "LastName"],
  ["Ken",       "Starr"],
  ["Kermit",    "Frog"]
];

然后你可以循环字典,像这样:

// Again, typed on the fly
var headers = dict[0];
var result = []
var o;
for (var i = 0 + 1; i < dict.length; i++) {
  o = {}
  for (j = 0; j < headers.length; j++) {
    o[headers[j]] = dict[i][j];
  }
  result.push(o);
}

【讨论】:

    【解决方案2】:

    Gzip 速度很快。 非常快。而且我非常有信心,它是精益物体运输的最佳(就实用性和效率而言)解决方案。

    为了说明这一点,我在我的一个临时站点上构建了一个快速示例。

    http://staging.svidgen.com/ajax/test-a.js 生成 5k 行简单数据并输出原始的、无污染的 JSON。

    $data = array();
    for ($i = 0; $i < 5000; $i++) {
        $data[] = array(
            'value-a' => $i,
            'value-b' => pow($i,2),
            'value-c' => pow($i,3)
        );
    }
    
    print json_encode($data);
    

    压缩后的响应为 65KB,请求、构建、序列化和传输大约需要 357ms。从等式中省略客户端大小的解析,即 吞吐量 182KB/s。考虑到传输的 274KB 原始数据,有效吞吐量为 767KB/s。响应如下所示:

    [{"value-a":0,"value-b":0,"value-c":0},{"value-a":1,"value-b":1,"value-c":1} /* etc. */]
    

    替代格式http://staging.svidgen.com/ajax/test-b.js 生成相同的 5k 行简单数据,但将数据重组为更高效的索引 JSON 序列化。

    $data = array();
    for ($i = 0; $i < 5000; $i++) {
        $data[] = array(
            'value-a' => $i,
            'value-b' => pow($i,2),
            'value-c' => pow($i,3)
        );
    }
    
    $out_index = array();
    $out = array();
    
    foreach ($data as $row) {
        $new_row = array();
        foreach ($row as $k => $v) {
            if (!isset($out_index[$k])) {
                $out_index[$k] = sizeof($out_index);
            }
            $new_row[$out_index[$k]] = $v;
        }
        $out[] = $new_row;
    }
    
    print json_encode(array(
        'index' => $out_index,
        'rows' => $out
    ));
    

    压缩后的响应为 59.4KB,请求、构建、序列化和传输大约需要 515ms。从等式中省略客户端大小的解析,即 吞吐量 115KB/s。考虑到传输的 128KB 原始数据,有效吞吐量为 248KB/s。响应如下所示:

    {"index":{"value-a":0,"value-b":1,"value-c":2},"rows":[[0,0,0],[1,1,1] /* etc. */ ]}
    

    因此,在我们相当简单的示例中,重组后的原始数据比原始原始数据小 50% 以上。但是,压缩后它只小了 9%。在这种情况下,成本是总请求时间增加了 44%。

    如果您编写了一个二进制库来重构数据,我希望您可以显着减少 44%。但是,它仍然不太可能值得。您需要它来序列化数据,而不需要比“正常”编码结构多 9% 的时间才能看到任何收益。

    避免重组或“替代序列化”命中的唯一方法是从头到尾以笨拙的索引方式在服务器端处理所有对象。而且,除非你真的迫于压力从你的硬件中获得每一个可以忽略不计的性能,否则这真的只是一个糟糕的主意。

    在这两种情况下,gzip 节省的空间远远超出了我们使用替代 JavaScript 可兼容格式所能达到的效果。

    (而且我们甚至没有考虑客户端大小的解析——这对于任何不“正常”的 JSON 或 XML 的东西都将是非常重要的。)

    结论

    只需使用内置的序列化库和 gzip。

    【讨论】:

    • 您的bs 是指位还是字节?通常,当您引用字节时,您应该将其大写。
    • @CodesInChaos 大小取自 Chrome 网络监视器。所以,我相信它们以 bytes 为单位。
    • @CodesInChaos ...感谢您指出歧义。我已经编辑了答案。
    • 你的数字很低,但不调查原因很难得出任何好的结论。
    • @CodesInChaos 我不会把结果当作福音。但是,它们确实说明了一个非常微不足道的记忆优势;即使不考虑时间成本(可以通过从头到尾使用更复杂的格式来避免),也可能使“聪明”解决方案的努力成为一项糟糕的投资。 (我要说明的普遍假设和接受的观点是,很难与完善的二进制库竞争。)
    【解决方案3】:
    1. 有非常快速的压缩库。因此,紧凑的格式并不一定比不太紧凑的格式加上压缩更好。

      我手头没有链接,但我认为一位前 protobuf 设计师推荐了这种方法。

    2. 查看MessagePack。这是一种相当紧凑的二进制格式,语义与 JSON 或 BSON 非常相似。

      短数组(最多 16 个元素)、映射(最多 16 对)和字符串(最多 32 个字节)具有单字节开销。小整数(-32 到 128)总共只占用一个字节。

    【讨论】:

    • MessagePack 很有趣。但是,它的价值似乎更多的是在缓存、日志记录等期间在服务器端节省空间。使用它的命名大公司(例如 Pintrest)似乎仍在使用标准 JSON + gzip 进行传输。 (根据你的第一点,如果我理解正确的话。)如果它包含一些数据,表明 MessagePack 是否倾向于产生比 gzip 压缩的 JSON 更高的有效吞吐量,我可以给这个答案一个赞成票。
    猜你喜欢
    • 1970-01-01
    • 2020-10-14
    • 2012-09-02
    • 2016-09-02
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 2018-04-30
    相关资源
    最近更新 更多