当前位置: 首页 > news >正文

从 .proto 到 Python:使用 Protocol Buffers 的完整实践指南

✨ 为什么使用 Protobuf?

Protocol Buffers(简称 protobuf)是 Google 推出的高效、跨语言、结构化数据序列化协议。相比 JSON / XML,它具备:

  • 📦 结构清晰:强类型 + 字段编号
  • 🚀 更高效:体积小,速度快
  • 🔁 跨语言:支持 Python / Java / Go / C++ 等
  • 🔐 序列化 & 反序列化自动完成

🧱 使用步骤概览

使用 protobuf 的标准流程如下:

1. 定义数据结构(.proto 文件)
2. 使用 protoc 编译生成 Python 文件
3. 在业务代码中导入并使用

✍️ Step 1:定义 .proto 文件

创建 history.proto 文件,内容如下:

syntax = "proto3";
package history;message Video {string video_id = 1;float video_time = 2;float watch_time = 3;int32 event_time = 4;
}message VideoHistory {repeated Video videos = 1;
}

📌 说明:

  • video_id:视频 ID
  • video_time:视频总时长
  • watch_time:观看时长
  • event_time:发生时间(秒级时间戳)
  • repeated:表示数组/列表

🛠️ Step 2:使用 protoc 编译生成 Python 文件

确保已安装 protoc,然后执行:

protoc --proto_path=. --python_out=./dto history.proto

执行后,自动生成 dto/history_pb2.py 文件,不要手动编辑这个文件,它是自动生成的。


🧪 Step 3:在 Python 中使用

from dto.history_pb2 import Video, VideoHistory# 构造单个视频数据
video = Video(video_id="vid_001",video_time=120.0,watch_time=90.0,event_time=1720001234
)# 构造历史记录
history = VideoHistory()
history.videos.append(video)# 序列化为二进制(可用于网络传输、存储)
binary_data = history.SerializeToString()# 反序列化回来
new_history = VideoHistory()
new_history.ParseFromString(binary_data)print("恢复的视频ID:", new_history.videos[0].video_id)

📦 Protobuf vs JSON 在 Redis 中的使用对比

对比项Protobuf(二进制)JSON(字符串)
体积✅ 小❌ 大
性能✅ 快(原生序列化)❌ 慢(字符串解析)
可读性❌ 差✅ 强
强类型结构✅ 有❌ 无
版本兼容性✅ 好❌ 差(需靠约定)
调试难度❌ 高✅ 低

🧱 Redis 存储方式:string vs list

Redis key: string(整体存 protobuf)

redis.set("user_click:123", history.SerializeToString())

适合:

  • 存储完整行为轨迹
  • 更新频率不高,或可加锁处理

Redis key: list(每条行为一个 protobuf)

redis.lpush("user_click:123", video.SerializeToString())
redis.ltrim("user_click:123", 0, 49)  # 限长

适合:

  • 高频点击写入
  • 实时滑窗建模(保留最近 N 条)
  • 更易扩展为 Kafka / 日志流

🔁 Protobuf + Redis 封装建议

def append_video(redis, uid: str, video: Video, max_len=50):key = f"user_click:{uid}"redis.lpush(key, video.SerializeToString())redis.ltrim(key, 0, max_len - 1)def get_user_clicks(redis, uid: str, limit=50):key = f"user_click:{uid}"raw_list = redis.lrange(key, 0, limit - 1)return [deserialize_video(raw) for raw in raw_list]def deserialize_video(raw: bytes) -> Video:v = Video()v.ParseFromString(raw)return v

http://www.lryc.cn/news/582919.html

相关文章:

  • 实战Linux进程状态观察:R、S、D、T、Z状态详解与实验模拟
  • 蓝桥杯 第十六届(2025)真题思路复盘解析
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | StickyNavbar(粘性导航栏)
  • SPI / I2C / UART 哪个更适合初学者?
  • 【C++】AVL树底层思想 and 大厂面试
  • 27.移除元素(快慢指针)
  • AI大模型应用-Ollama本地千问大模型stream流乱码
  • HDLBits刷题笔记和一些拓展知识(十一)
  • 学习设计模式《十七》——状态模式
  • 美团Java面试分享
  • 基于模板设计模式开发优惠券推送功能以及对过期优惠卷进行定时清理
  • 在Docker中安装nexus3(作为maven私服)
  • [创业之路-489]:企业经营层 - 营销 - 如何将缺点转化为特点、再将特点转化为卖点
  • Java基础回顾(1)
  • 【无标题】导出pdf
  • Spring Boot 企业项目技术选型
  • Splunk练习 Boss of the SOC V1
  • JVM本地内存的使用监控情况
  • JVM 为什么使用元空间(Metaspace)替换了永久代(PermGen)?——深入理解 Java 方法区与类元数据存储的演进
  • 征程 6|工具链量化简介与代码实操
  • Redis 缓存进阶篇,缓存真实数据和缓存文件指针最佳实现?如何选择?
  • 当Powerbi遇到quickbi,性能优化方式对比
  • 玩具语音方案选型决策OTP vs Flash 的成本功耗与灵活性
  • BERT代码简单笔记
  • 台式电脑如何连wifi 快速连接方法
  • 无缝高清矩阵与画面分割器的区别
  • numpy数据分析知识总结
  • Web前端:not(否定伪类选择器)
  • boost中boost::noncopyalbe和boost::ignore_unused的使用详解和实战示例
  • 网络--初级