Python高级技术之:`Python`的`msgpack`和`json`:序列化和反序列化的性能对比。

各位观众老爷,晚上好!我是你们今晚的“序列化段子手”兼“反序列化老司机”,今天咱就来聊聊Python世界里两个扛把子的序列化工具:msgpackjson

咱们的口号是:用最骚的操作,把数据玩明白!

第一幕:啥是序列化?为啥要它?

别急,先给大家来段“灵魂拷问”:为啥要有序列化这玩意儿?

想象一下,你辛辛苦苦用Python创造了一个对象,里面塞满了各种数据,比如:

my_data = {
    "name": "张三",
    "age": 30,
    "city": "北京",
    "hobbies": ["coding", "reading", "gaming"],
    "address": {
        "street": "长安街1号",
        "zipcode": "100000"
    }
}

这数据对你来说,那是亲切无比,一看就懂。但是!计算机的世界里,数据是以二进制形式存储的。如果直接把这个Python对象扔到硬盘上,或者通过网络传给别人,那简直就是“鸡同鸭讲”,对方根本看不懂。

所以,我们需要一种“翻译官”,把Python对象翻译成一种通用的格式,让不同的程序、不同的语言都能理解。这个“翻译”的过程,就叫做序列化 (Serialization)

反过来,把通用的格式再翻译回Python对象,就是反序列化 (Deserialization)

简单来说,序列化就是把数据变成一串字节,反序列化就是把这串字节还原成数据。

第二幕:两位主角闪亮登场:json vs msgpack

现在,两位主角要登场了,分别是jsonmsgpack

  • json (JavaScript Object Notation): 老牌选手,江湖地位稳固。它是一种基于文本的格式,人类可读性强,几乎所有编程语言都支持。

  • msgpack (MessagePack): 后起之秀,性能怪兽。它是一种基于二进制的格式,体积小,速度快,但人类可读性较差。

用人话来说,json就像是写给人类看的“作文”,字迹工整,容易理解;msgpack就像是给机器看的“电报”,简洁高效,但需要专门的“解码器”。

第三幕:json的温柔一面

json的优点在于它的“平易近人”。

  • 易于阅读和调试: json数据可以直接用文本编辑器打开,方便查看和修改。
  • 广泛支持: 几乎所有编程语言和平台都支持json,兼容性极佳。

Python自带了json模块,使用起来非常简单:

import json

my_data = {
    "name": "张三",
    "age": 30,
    "city": "北京"
}

# 序列化:Python对象 -> json字符串
json_string = json.dumps(my_data, ensure_ascii=False, indent=4) # ensure_ascii=False解决中文乱码,indent=4美化输出
print("JSON字符串:")
print(json_string)

# 反序列化:json字符串 -> Python对象
loaded_data = json.loads(json_string)
print("n反序列化后的Python对象:")
print(loaded_data)

输出结果:

JSON字符串:
{
    "name": "张三",
    "age": 30,
    "city": "北京"
}

反序列化后的Python对象:
{'name': '张三', 'age': 30, 'city': '北京'}

json.dumps()函数将Python对象序列化成json字符串。ensure_ascii=False是为了防止中文乱码,indent=4是为了让输出的json字符串更美观。

json.loads()函数将json字符串反序列化成Python对象。

第四幕:msgpack的狂野一面

msgpack的优点在于它的“速度与激情”。

  • 更小的体积: msgpack使用二进制格式,可以更有效地压缩数据,减少存储空间和网络传输带宽。
  • 更快的速度: msgpack的序列化和反序列化速度通常比json更快,尤其是在处理大量数据时。

要使用msgpack,需要先安装它:

pip install msgpack

然后,就可以像这样使用它:

import msgpack

my_data = {
    "name": "张三",
    "age": 30,
    "city": "北京"
}

# 序列化:Python对象 -> msgpack字节串
packed_data = msgpack.packb(my_data, use_bin_type=True) #use_bin_type=True解决bytes类型问题
print("msgpack字节串:")
print(packed_data)

# 反序列化:msgpack字节串 -> Python对象
unpacked_data = msgpack.unpackb(packed_data, raw=False) # raw=False 解决bytes类型问题
print("n反序列化后的Python对象:")
print(unpacked_data)

输出结果:

msgpack字节串:
b'x83xa4namexa6xe5xbcxa0xe4xb8x89xa3agex1exa4cityxa6xe5x8cx97xe4xbaxac'

反序列化后的Python对象:
{'name': '张三', 'age': 30, 'city': '北京'}

msgpack.packb()函数将Python对象序列化成msgpack字节串。use_bin_type=True是为了兼容Python 3的bytes类型。

msgpack.unpackb()函数将msgpack字节串反序列化成Python对象。raw=False是为了将字节串类型的键和值转换为字符串类型。

第五幕:性能大比拼:json vs msgpack

光说不练假把式,咱得来一场真刀真枪的性能测试,看看jsonmsgpack到底谁更快。

import json
import msgpack
import time
import random

# 生成随机数据
def generate_data(size):
    data = []
    for _ in range(size):
        item = {
            "id": random.randint(1, 1000),
            "name": "商品" + str(random.randint(1, 100)),
            "price": round(random.uniform(10, 1000), 2),
            "description": "这是一段很长的商品描述" * 5,
            "features": ["feature1", "feature2", "feature3"]
        }
        data.append(item)
    return data

data_sizes = [100, 1000, 10000] # 测试不同数据量
num_iterations = 100  # 重复测试次数,取平均值

for size in data_sizes:
    data = generate_data(size)

    # JSON 序列化和反序列化
    start_time = time.time()
    for _ in range(num_iterations):
        json_string = json.dumps(data, ensure_ascii=False)
        json_data = json.loads(json_string)
    json_time = (time.time() - start_time) / num_iterations

    # msgpack 序列化和反序列化
    start_time = time.time()
    for _ in range(num_iterations):
        packed_data = msgpack.packb(data, use_bin_type=True)
        unpacked_data = msgpack.unpackb(packed_data, raw=False)
    msgpack_time = (time.time() - start_time) / num_iterations

    # 打印结果
    print(f"数据量: {size}")
    print(f"  JSON: {json_time:.6f} 秒")
    print(f"  msgpack: {msgpack_time:.6f} 秒")

    # 计算体积大小
    json_size = len(json_string.encode('utf-8'))
    msgpack_size = len(packed_data)

    print(f"  JSON 大小: {json_size} 字节")
    print(f"  msgpack 大小: {msgpack_size} 字节")
    print(f"  msgpack 体积缩小比例: {(1 - msgpack_size / json_size) * 100:.2f}%")

    print("-" * 30)

这个代码会生成不同大小的随机数据,然后分别用jsonmsgpack进行序列化和反序列化,并记录时间。最后,还会打印出json字符串和msgpack字节串的大小,以及msgpack相对于json的体积缩小比例。

运行结果(示例):

数据量: 100
  JSON: 0.001448 秒
  msgpack: 0.000955 秒
  JSON 大小: 54586 字节
  msgpack 大小: 37564 字节
  msgpack 体积缩小比例: 31.18%
------------------------------
数据量: 1000
  JSON: 0.012585 秒
  msgpack: 0.007178 秒
  JSON 大小: 546079 字节
  msgpack 大小: 375455 字节
  msgpack 体积缩小比例: 31.24%
------------------------------
数据量: 10000
  JSON: 0.122115 秒
  msgpack: 0.068266 秒
  JSON 大小: 5460772 字节
  msgpack 大小: 3754684 字节
  msgpack 体积缩小比例: 31.24%
------------------------------

从结果可以看出,msgpack在性能和体积上都优于json。随着数据量的增加,msgpack的优势更加明显。

第六幕:选择困难症?别怕,我来帮你!

面对jsonmsgpack,到底该选哪个?别慌,我来给你支招:

特性 json msgpack 适用场景
格式 文本 二进制
可读性
性能 较慢 较快
体积 较大 较小
兼容性 极好 良好(需要安装msgpack库)
主要用途 Web API,配置文件,数据交换 消息队列,RPC,游戏开发,高性能数据存储与传输
适用场景举例 前后端数据交互,需要调试和人工查看数据内容 高并发场景,需要快速序列化和反序列化,对数据体积敏感,例如:实时游戏服务器、大规模分布式系统,特别是内部服务之间通信。对于存储空间有限的设备(嵌入式)也很有用。

简单总结:

  • 如果你的首要考虑是可读性和兼容性,并且对性能要求不高,那就选json 比如,Web API的数据交换,配置文件等等。
  • 如果你的首要考虑是性能和体积,并且可以接受一定的学习成本,那就选msgpack 比如,消息队列,RPC,游戏开发,高性能数据存储等等。

第七幕:注意事项,避坑指南

在使用jsonmsgpack时,还有一些需要注意的地方:

  • json不支持二进制数据: 如果你的数据中包含二进制数据(比如图片、视频),需要先进行Base64编码,然后再序列化成json字符串。
  • msgpack对数据类型有要求: msgpack对某些数据类型的处理方式可能与json不同。比如,json会将所有数字都转换成浮点数,而msgpack会保留整数的类型。
  • 版本兼容性: json的兼容性很好,但msgpack不同版本之间可能存在兼容性问题,需要注意保持版本一致。

第八幕:总结陈词

好了,今天的“序列化段子”就讲到这里。希望大家通过今天的学习,能够更好地理解jsonmsgpack,并根据自己的实际情况选择合适的序列化工具。

记住,没有最好的工具,只有最适合你的工具。

最后,祝大家编程愉快,bug少一点,头发多一点!

散会!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注