使用Google V8实现最快的JavaScript对象序列化

26

我需要对具有1-100个混合类型属性的中等复杂对象进行序列化。

最初使用了JSON,然后切换到较快的BSON。

编码10000个样本对象

JSON:        1807mS
BSON:        1687mS
MessagePack: 2644mS (JS, modified for BinaryF)

我希望能够实现数量级的增长,因为它对系统的其他部分造成了非常糟糕的影响。

转向BSON的动机之一是要编码二进制数据,因此JSON不适用(现在)。因为它简单地跳过对象中存在的二进制数据,所以在这些基准测试中“作弊”。

分析了BSON性能瓶颈

  • (无法避免?)将UTF16 V8 JS字符串转换为UTF8。
  • BSON库内的malloc和字符串操作

BSON编码器基于Mongo BSON库。

本机V8二进制序列化程序可能很棒,但由于JSON是本地的且快速的序列化方式,我担心即使使用该程序也可能无法提供答案。也许我最好的选择是优化BSON库或自己编写BSON库,然后找到更有效地从V8中提取字符串的方法。一种策略可能是向BSON添加UTF16支持。

所以我来这里寻求想法,也许是理智的检查。

编辑

添加了MessagePack基准测试。这是从原始JS修改而来,使用BinaryF。C++ MessagePack库可能会提供进一步的改进,我可能会对其进行孤立测试,以直接与BSON库进行比较。


1
也许您可以提供一个 http://jsperf.com/ 测试用例来帮助理解您需要存储的数据类型。 - Gary Green
只是标准的 JS 对象:{param1:"名称",param2:{paramA:1,paramB:[0x0,0x1,0x2],paramC:<二进制>}},最多具有 100 个属性,任意嵌套,其中一些将包含使用 CommonJS BinaryF 的字节数组。如果没有 BinaryF 和 BSON 序列化程序,就无法进行任何有用的比较。 - user172783
1
我已经很久没有运行这些测试了。据我所知,window.btoa/atob是base64编码,因此需要进行额外的处理(例如JSON.stringify/parse)才能将数据转换为/从base64兼容数据,因此速度会更慢。 - user172783
@McTrousers 很有趣能看到你最终想出了什么解决方案。我也在寻找一种持久化 V8 对象的方法,但迄今为止还没有找到足够好的解决方案。 - Venemo
自从这个问题被提出并且问题中的基准测试运行以来的五年里,v8和其他JS引擎已经对JSON de/serialization进行了大量优化。现在,JSON的速度比BSON快约8倍,而最快的msgpack库(https://www.npmjs.com/package/msgpack-lite)比JSON略慢。 - ZachB
显示剩余3条评论
4个回答

20
我最近(2020年)写了一篇文章和基准测试,比较了JavaScript中的二进制序列化库。比较了以下格式和库:
Protocol Buffer: protobuf-js, pbf, protons, google-protobuf Avro: avsc BSON: bson BSER: bser JSBinary: js-binary 根据当前基准测试结果,我会按以下顺序排列前几个库(值越高越好,测量值以比JSON更快的速度x表示):
  1. avsc:10倍编码,3-10倍解码
  2. js-binary:2倍编码,2-8倍解码
  3. protobuf-js:0.5-1倍编码,2-6倍解码
  4. pbf:1.2倍编码,1.0倍解码
  5. bser:0.5倍编码,0.5倍解码
  6. bson:0.5倍编码,0.7倍解码
由于根据其NPM描述,msgpack目前比内置的JSON库慢,所以我没有将其包含在基准测试中。
有关详细信息,请参见完整的文章

10

在序列化/反序列化方面,protobuf 是相当难以击败的。 我不知道您是否可以更换传输协议。 但如果可以的话,一定要考虑使用 protobuf。

查看所有对 Protocol Buffers versus JSON or BSON 的回答。

被接受的答案选择了thrift。 但是它比 protobuf 慢。 我怀疑它之所以被选择,是因为它易于使用 (与 Java 一起) 而不是速度快。 这些Java基准测试表明了这一点。
值得注意的是:

  • MongoDB-BSON 45042
  • protobuf 6539
  • protostuff/protobuf 3318

基准测试是使用 Java 编写的,我想你可以获得接近 protobuf 的 protostuff 实现的速度,即快 13.5 倍。 最坏的情况(如果出于某种原因 Java 只是更适合序列化),您也不会比普通未经优化的 protobuf 实现运行速度慢,它的运行速度是快 6.8 倍。


感谢提供基准测试数据。由于数据是用户生成的,所以PB协议需要携带键值对,这可能会削弱一些性能优势,但我预计它仍然能够大幅领先。不过,它不支持UTF16,所以添加该类型应该不难。 - user172783
我一直在使用BSON,并逐步进行优化。但是在某些时候,我可能会回到protobuf。谢谢。 - user172783

4

看看MessagePack。它与JSON兼容。从文档中可以得到以下信息:

快速且紧凑的序列化

MessagePack是一个基于二进制的高效对象序列化库。它使得结构化对象之间可以在许多语言之间交换,就像JSON一样。但与JSON不同的是,它非常快速和小巧。

典型的小整数(如标志或错误代码)仅保存在1个字节中,而典型的短字符串除了字符串本身的长度外只需要1个字节。[1,2,3](3个元素的数组)使用MessagePack序列化后只需4个字节,如下所示:


太棒了!绝对值得测试!我会先尝试JS实现。 - user172783
3
现在再次对比测试MessagePack和JSON :) JSON 完全压倒它,bson 也一样(即使是 C++ 绑定的原生 bson)。我知道这个问题已经大约5年了,但是,现在很难打败JSON。不过我得承认MsgPack在他们的 GitHub 页面上承认了失败,哈哈。-- 它们之间的差距甚至可以说是天壤之别。 - NiCk Newman
我刚刚在我的一个测试例子中比较了序列化字符串返回的MessagePack和JSON。与JSON.stringify生成长度为1011的字符串相比,MessagePack字符串的长度为2231。 - Mudaser Ali

0

如果您更关心反序列化速度,请看看JBB(JavaScript二进制包)库。它比BSON或MsgPack更快。

从维基百科,页面JBB vs BSON vs MsgPack

...

  • JBB的解码速度比二进制JSON(BSON)快约70%,比MsgPack快约30%,即使只有一个负面测试用例(#3)。
  • JBB创建的文件(即使是它们的压缩版本)比二进制JSON(BSON)小约61%,比MsgPack小约55%。

...

不幸的是,它不是一种流格式,这意味着您必须离线预处理数据。但是有一个将其转换为流格式的计划(请检查里程碑)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接