





















import json
import xml.etree.ElementTree as ET
import time
import sys
from google.protobuf.json_format import MessageToJson, Parse
from person_pb2 import Person as ProtobufPerson# 导入protobuf生成类(需先编译person.proto)
# 生成命令:protoc --python_out=. person.proto
# 定义相同的数据结构
sample_data = {
"name": "张三",
"id": 12345,
"email": "zhangsan@example.com",
"phones": [
{"number": "13800138000", "type": "MOBILE"},
{"number": "010-12345678", "type": "WORK"}
],
"address": {
"street": "科技园路123号",
"city": "北京",
"zip_code": "100000"
}
}
def json_serialization_demo():
"""JSON序列化演示"""
print("=== JSON演示 ===")
# 序列化
start = time.perf_counter_ns()
json_str = json.dumps(sample_data, ensure_ascii=False)
json_time = time.perf_counter_ns() - start
json_size = len(json_str.encode('utf-8'))
# 反序列化
start = time.perf_counter_ns()
decoded_data = json.loads(json_str)
json_decode_time = time.perf_counter_ns() - start
print(f"数据大小: {json_size} 字节")
print(f"序列化时间: {json_time} ns")
print(f"反序列化时间: {json_decode_time} ns")
print(f"序列化后数据预览: {json_str[:80]}...")
return json_size, json_time, json_decode_time, json_str
def xml_serialization_demo():
"""XML序列化演示"""
print("\n=== XML演示 ===")
# 创建XML结构
person = ET.Element("person")
ET.SubElement(person, "name").text = sample_data["name"]
ET.SubElement(person, "id").text = str(sample_data["id"])
ET.SubElement(person, "email").text = sample_data["email"]
phones = ET.SubElement(person, "phones")
for phone in sample_data["phones"]:
phone_elem = ET.SubElement(phones, "phone")
ET.SubElement(phone_elem, "number").text = phone["number"]
ET.SubElement(phone_elem, "type").text = phone["type"]
address = ET.SubElement(person, "address")
ET.SubElement(address, "street").text = sample_data["address"]["street"]
ET.SubElement(address, "city").text = sample_data["address"]["city"]
ET.SubElement(address, "zip_code").text = sample_data["address"]["zip_code"]
# 序列化
start = time.perf_counter_ns()
xml_str = ET.tostring(person, encoding='unicode', method='xml')
xml_time = time.perf_counter_ns() - start
xml_size = len(xml_str.encode('utf-8'))
# 反序列化
start = time.perf_counter_ns()
root = ET.fromstring(xml_str)
# 解析XML数据
xml_data = {
"name": root.find("name").text,
"id": int(root.find("id").text),
"email": root.find("email").text,
"phones": [],
"address": {}
}
for phone_elem in root.find("phones").findall("phone"):
xml_data["phones"].append({
"number": phone_elem.find("number").text,
"type": phone_elem.find("type").text
})
address_elem = root.find("address")
xml_data["address"]["street"] = address_elem.find("street").text
xml_data["address"]["city"] = address_elem.find("city").text
xml_data["address"]["zip_code"] = address_elem.find("zip_code").text
xml_decode_time = time.perf_counter_ns() - start
print(f"数据大小: {xml_size} 字节")
print(f"序列化时间: {xml_time} ns")
print(f"反序列化时间: {xml_decode_time} ns")
print(f"序列化后数据预览: {xml_str[:80]}...")
return xml_size, xml_time, xml_decode_time, xml_str
def protobuf_serialization_demo():
"""Protobuf序列化演示"""
print("\n=== Protobuf演示 ===")
# 创建Protobuf对象
person = ProtobufPerson()
person.name = sample_data["name"]
person.id = sample_data["id"]
person.email = sample_data["email"]
# 添加电话
for phone in sample_data["phones"]:
phone_entry = person.phones.add()
phone_entry.number = phone["number"]
if phone["type"] == "MOBILE":
phone_entry.type = ProtobufPerson.PhoneType.MOBILE
else:
phone_entry.type = ProtobufPerson.PhoneType.WORK
# 设置地址
person.address.street = sample_data["address"]["street"]
person.address.city = sample_data["address"]["city"]
person.address.zip_code = sample_data["address"]["zip_code"]
# 序列化
start = time.perf_counter_ns()
binary_data = person.SerializeToString()
pb_time = time.perf_counter_ns() - start
pb_size = len(binary_data)
# 反序列化
start = time.perf_counter_ns()
decoded_person = ProtobufPerson()
decoded_person.ParseFromString(binary_data)
pb_decode_time = time.perf_counter_ns() - start
# 转换为字典以便比较
pb_dict = {
"name": decoded_person.name,
"id": decoded_person.id,
"email": decoded_person.email,
"phones": [
{
"number": phone.number,
"type": ProtobufPerson.PhoneType.Name(phone.type)
}
for phone in decoded_person.phones
],
"address": {
"street": decoded_person.address.street,
"city": decoded_person.address.city,
"zip_code": decoded_person.address.zip_code
}
}
print(f"数据大小: {pb_size} 字节")
print(f"序列化时间: {pb_time} ns")
print(f"反序列化时间: {pb_decode_time} ns")
print(f"序列化后数据预览: 二进制数据,不可直接阅读")
# 将protobuf转换为JSON用于显示
json_from_pb = MessageToJson(decoded_person, preserving_proto_field_name=True)
print(f"转换为JSON后预览: {json_from_pb[:80]}...")
return pb_size, pb_time, pb_decode_time, binary_data
def performance_comparison():
"""性能对比总结"""
print("\n" + "="*60)
print("性能对比总结")
print("="*60)
# 运行所有演示
json_results = json_serialization_demo()
xml_results = xml_serialization_demo()
pb_results = protobuf_serialization_demo()
print("\n" + "="*60)
print("详细对比表")
print("="*60)
print(f"{'格式':<10} | {'大小(字节)':<12} | {'序列化时间(ns)':<16} | {'反序列化时间(ns)':<18} | {'压缩率'}")
print("-"*80)
formats = ["JSON", "XML", "Protobuf"]
results = [json_results, xml_results, pb_results]
for i in range(3):
size, ser_time, deser_time, _ = results[i]
compression_rate = f"{size/json_results[0]*100:.1f}%"
print(f"{formats[i]:<10} | {size:<12} | {ser_time:<16} | {deser_time:<18} | {compression_rate}")
print("\n" + "="*60)
print("Protobuf优势总结")
print("="*60)
print(f"1. 数据大小:比JSON小{json_results[0]/pb_results[0]:.1f}倍,比XML小{xml_results[0]/pb_results[0]:.1f}倍")
print(f"2. 序列化速度:比JSON快{json_results[1]/pb_results[1]:.1f}倍,比XML快{xml_results[1]/pb_results[1]:.1f}倍")
print(f"3. 反序列化速度:比JSON快{json_results[2]/pb_results[2]:.1f}倍,比XML快{xml_results[2]/pb_results[2]:.1f}倍")
print(f"4. 类型安全:有严格的类型检查和编译时验证")
print(f"5. 向后兼容:支持字段的添加和删除而不破坏旧版本")
# 验证数据一致性
print("\n" + "="*60)
print("数据一致性验证")
print("="*60)
# 重新解析所有格式并比较
json_data = json.loads(json_results[3])
root = ET.fromstring(xml_results[3])
# 解析XML数据(简化版)
xml_data = {
"name": root.find("name").text,
"id": int(root.find("id").text),
"email": root.find("email").text
}
decoded_person = ProtobufPerson()
decoded_person.ParseFromString(pb_results[3])
pb_dict = {
"name": decoded_person.name,
"id": decoded_person.id,
"email": decoded_person.email
}
print("所有格式解析出的核心数据一致:")
print(f" JSON: name={json_data['name']}, id={json_data['id']}")
print(f" XML: name={xml_data['name']}, id={xml_data['id']}")
print(f" Proto: name={pb_dict['name']}, id={pb_dict['id']}")
if __name__ == "__main__":
# 首先需要定义并编译person.proto文件
# person.proto内容如下:
"""
syntax = "proto3";
package demo;
message Person {
string name = 1;
int32 id = 2;
string email = 3;
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
message Address {
string street = 1;
string city = 2;
string zip_code = 3;
}
Address address = 5;
}
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
"""
print("注意:运行此示例前,请确保:")
print("1. 已安装protobuf: pip install protobuf")
print("2. 已创建person.proto文件")
print("3. 已编译proto文件: protoc --python_out=. person.proto")
print("4. person_pb2.py文件已存在\n")
try:
performance_comparison()
except ImportError as e:
print(f"错误:{e}")
print("请确保已正确编译person.proto文件")
except Exception as e:
print(f"运行时错误:{e}")
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。