有时因为业务须要,要将一个 Lua Table 序列化,如果不在乎序列化后果的可读性,能够间接将 Table 序列化成二进制数据块,如果须要后果的可读性,能够将 Table 序列化成字符串。
要序列化的内容
因为 Lua 的 Table 中能够保留各种各样的内容,不可能都序列化,而且根本也不会有这种需要,比方像是 Function 这种变量,序列化进去并无意义,因为在另一个环境下反序列化当前就不能用了。
出于这个起因,Function 和 Thread 变量不论是 key 还是 value 都不会解决。如果 key 是 Table 变量,则也不解决,同时 Table 中不能有对其它 Table 的循环援用。
尽管看起来有一些限度,然而因为序列化 Table 个别都是用在保留或者发送上,所以其实自身就基本上不会有这种受限制的需要。
二进制
将 Table 序列化为二进制数据块的速度是最快的,体积也是最小的,如果没有可读性要求,且序列化远比反序列化的次数多,那就果决抉择序列化成二进制。
云风大佬有一个现成的实现能够间接拿来用 lua-serialize,本人实现一个也不难,就是应用 Lua 提供的 C Api 遍历 Table,而后依据 key 和 value 的类型,一直写入到一个能够动静扩容的内存块链表中,全副写入实现当前再将链表中的所有块拷贝进一个间断内存中。
除了后果没有可读性以外,序列化成二进制还有一个毛病就是后果要反序列化成 Table 的时候仍然须要逆向解析一遍。
字符串
序列化成字符串的长处是,后果可读性好,而且不须要额定实现反序列化,能够间接应用 load 来加载字符串实现反序列化。
Lua 实现
用 Lua 来实现是最顺畅最简略的,不必写 C 代码,也不须要编译。如果没有高频应用的话,用 Lua 序列化就足够用了。
有一个十分好的第三方实现能够用来解决这个问题,serpent,功能强大,不仅能够序列化,还能够将 Table 以可读形式打印进去。
C/C++ 实现
因为工作须要高频将 Table 序列化成字符串,且单个 Table 数据量也不少。所以始终想找一个 C/C++ 语言的实现版本,然而 github 上找了半天也没找到。起初周末抽了个工夫本人实现了一个 luaseri-cpp。
实现并不简单,然而碰到了一个问题,就是 snprintf 在解决 double 的时候十分慢。搜寻当前发现了一个十分切合我需要的我的项目,dtoa-benchmark,是腾讯的大佬叶劲峰实现的,学 C++ 的应该都据说过他,《C++ Primer 5th》中文版的审校之一。该我的项目给出了他对 Grisu2 算法的实现,效率是挺好的,就间接拿来用了。
性能比照
比照以上的三种实现,通过测试,能够得出性能的大抵比照后果。
在序列化一个大型 Table 的时候,以 lua-serialize 的用时为基准 n,luaseri-cpp 的用时为 1.8n – 2n,serpent 的用时大略为 40n 左右。lua-serialize 序列化进去的后果也比其余两种后果的长度小很多,具体比例与 Table 中的数据有关系,当 Table 中的数字越多时,长度差距越大。
反序列化的时候,lua-serialize 须要应用它自带的反序列化函数,同样以它的反序列化事件为基准 m,序列化为字符串的实现应用 Lua 自带的 load 函数加载字符串失去 Table,应用的工夫大略在 2m 左右。
能够看到 lua-serialize 无论在序列化和反序列化上工夫都占优不少,在空间应用上劣势更大。所以如果不须要后果的可读性的话,间接应用它即可。如果须要可读性,那么应用 luaseri-cpp 的效率也是比拟快的。如果不喜爱用 C 库,或者对性能没要求的状况下能够应用 serpent 来实现。
感觉能够在开发版本序列化成字符串,不便调试,在线上版本应用 lua-serialize,效率和空间都能占优不少。