protobuf为什么快

protobuf为什么快

protobuf为什么快_protostaff-CSDN博客

为什么protobuf这么快_protocolbuffer为什么效率高-CSDN博客

说明

Protobuf(Protocol Buffers)是由 Google 开发的一种轻量级、高效的数据交换格式,它被用于结构化数据的序列化、反序列化和传输。相比于 XML 和 JSON 等文本格式,Protobuf 具有更小的数据体积、更快的解析速度和更强的可扩展性。

核心思想:使用协议(Protocol)来定义数据的结构和编码方式。使用 Protobuf,可以先定义数据的结构和各字段的类型、字段等信息,然后使用Protobuf提供的编译器生成对应的代码,用于序列化和反序列化数据。由于 Protobuf 是基于二进制编码的,因此可以在数据传输和存储中实现更高效的数据交换,同时也可以跨语言使用,如下所示
b6aa58081f3346498615bfad50decd8a

总结

Protobuf为什么这么快?_哔哩哔哩_bilibili

类型:

  • 基本都是正数(varint):int32、int64
  • 既有正数又有负数(使用zigzag + varint优化):sint32、sint64
  • 数据很大(tag使用varint,数据使用固定长度4字节或者8字节):fixed32、fixed64
  • 字符串类型(Tag+Length+Value):string

image-20260717182512931

格式:image-20260717182559533image-20260717182543568

tag :高位(字段序号) + 低三位(字段类型)

体积小、传输快:编号代替字段名,传输的纯是数据本身,体积通常比 JSON 小 30% 以上,网络传输自然就快。

格式:tag+数据+tag+数据+tag+length+数据

  • 数字就是:tag+数据
    • Varint + ZigZag
  • 字符串:tag+length+数据
    • Tag-Length-Value
  • tag = makeTag返回值 = 高位(字段序号) + 低三位(字段类型)
  • 小端序存储
  • 存储的时候怎么知道这个字段是tag还是数据:
    • 最高位1表示这个是上一个字节的部分,最高位是0表示是tag
    • 每个字节只有7位数字表示内容,最高位表示是不是tag
    • 二进制按这种存储,解析按这样解析,就会快!!!

image-20260717181903036

AI回答

  • 格式是 tag+数据+tag+数据,直接二进制的,没有额外的字段名存储

    • 这样体积小,体积小对应的传输就快

    • 解析快,也是因为是二进制,且有预定义的 Schema,可以流式顺序读取,直接往对应的结构体里填充数据,甚至支持零拷贝。

    • AI解答这个回答:

      1. 你的核心观点(完全正确,直接说)

        • 传输快:无字段名,只有Tag+Value,体积通常是JSON的1/3,网络IO时间短。
        • 解析快:无需文本分词,基于预定义Schema(.proto文件)直接内存填充,支持零拷贝。
      2. 补上“为什么比压缩过的JSON还快”的杀招:Varint

        • JSON即使压缩成gzip,服务端解压解析文本是两步,CPU开销大。
        • Protobuf用了Varint(变长整数)编码。整数不固定占4字节,数字小(如1)只占1个字节。更关键的是,它用位运算(位移和异或)取代了JSON解析时的乘除法和字符转换,这是CPU指令级别的降维打击。
      3. 补上“为什么填充内存快”的杀招:无需反序列化两次

        • JSON解析通常是:读文本 -> 生成DOM树/Map -> 再转成对象,产生大量临时对象,GC(垃圾回收)压力大。
        • Protobuf生成的代码直接操作内存偏移量(offset)。读到Tag,就知道把这个Value直接写到结构体的哪个内存地址上。一次遍历,边读边填,且内存连续,对CPU缓存极友好。

      终极回答模板(融合版)

      “Protobuf快是空间时间双赢的结果。

      空间上,它用Tag代替字段名,结合Varint变长编码,让数据包极小,传输快。

      时间上,它是二进制协议,解析时省去了JSON繁琐的字符转数字和键值查找。加上有预定义的Schema,解析器能顺序读取,通过内存偏移量直接赋值给结构体,省去了中间对象创建,GC压力小,所以极快。”

  • 第一,它是二进制协议,没有“废话”。
    JSON 和 XML 是文本格式,会传输大量的键名、引号、花括号这些元数据。而 Protobuf 用字段编号代替字段名,传输的纯是数据本身,体积通常比 JSON 小 30% 以上,网络传输自然就快。

    第二,编解码过程中省去了字符处理。
    JSON 解析需要做文本分词、处理 Unicode、把字符串数字转成整数,这些都是 CPU 密集操作。而 Protobuf 直接操作二进制字节流,用的是位运算和位移,没有字符编码转换的开销。

    第三,采用了高效的变长编码(Varint)。
    对于整数,它不用固定 4 个或 8 个字节,数值越小占的字节越少。比如数字 1 只占 1 个字节,这就进一步压缩了数据量。

    第四,解析时不需要构建树形结构。
    JSON 需要先完整加载数据、构建 DOM 树再查找字段,内存分配多、GC 压力大。而 Protobuf 因为有预定义的 Schema,可以流式顺序读取,直接往对应的结构体里填充数据,甚至支持零拷贝。

    总结一句话: Protobuf 用牺牲可读性依赖预定义 Schema 为代价,换来了极致的压缩率和直接的内存填充,所以编解码和传输都快。

JSON\XML是怎么传输的,为什么慢?

JSON 传输的是"字符的二进制编码"(比如 ASCII 码),而 Protobuf 传输的是"数值的二进制表示"。前者是"文本流",后者是"数据流"。

  • JSON 和 XML 本质上是文本协议,传输和解析慢的核心原因有三点:

    • 第一,传输时携带了大量冗余信息。 字段名、引号、花括号、标签这些全是"传输开销",有效数据占比低,网络 IO 时间长。

    • 第二,解析时需要做文本分词和类型转换。 数字在文本里是字符 '1' '2' '3',要转成真正的数字需要乘法和累加;真假值(true/false)需要字符串比较;这些操作远不如直接读二进制快。

    • 第三,解析时需要构建树形结构。 JSON 要先生成 DOM 树或哈希表,XML 要构建 DOM 树,然后再从中查找字段,中间产生大量临时对象,GC 压力大。

    • 核心一句话: JSON/XML 慢在"人类可读"这四个字上——为了让人能看懂,付出了巨大的编解码代价。

  • JSON 示例

    {"user_id": 12345, "user_name": "张三", "age": 25}
    
    • 实际传输的字节(UTF-8):每一个字符都会变成一个ASCII 码表示

      { " u s e r _ i d " :   1 2 3 4 5 ,   " u s e r _ n a m e " :   " 张 三 " ,   " a g e " :   2 5 }
      
    • 有效数据:12345(5字节)+ 张三(6字节)+ 25(2字节)= 13 字节

    • 冗余数据:花括号、引号、冒号、逗号、键名 = 约 35+ 字节

    • 每一个字符都会变成一个ASCII 码表示:

    • 例如:

        字符 '1' → ASCII 码 0x31
        字符 '2' → ASCII 码 0x32
        字符 '3' → ASCII 码 0x33
        字符 '4' → ASCII 码 0x34
        字符 '5' → ASCII 码 0x35
        # JSON网络传输的字节流:31 32 33 34 35  (5 个字节)
        
        数字 12345 → 二进制是 0x3039 → Varint 编码后 → 0xB9 0x60
        # Protobuf网络传输的字节流:B9 60  (2 个字节)
        
        看出区别了吗?同样是 0 和 1,JSON 传的是"数字的字符表示",Protobuf 传的是"数字本身"。
      

序列化方式、或者说传输信息时使用的方式除了xml、json、protobuf还有哪些?

  • 第一类,文本型:XML、JSON,以及更紧凑的 YAMLTOML,主要用于配置文件和人机交互。

  • 第二类,通用二进制型ProtobufThriftAvro,主要用于微服务 RPC 通信,兼顾性能和跨语言。

  • 第三类,高性能极致型FlatBuffersCap'n Proto,支持零拷贝,解析时不需要反序列化,直接访问内存。

  • 第四类,语言专属型:Java 的 SerializableKryo、Go 的 gob、Python 的 pickle,主要用于同语言进程间通信或本地持久化。

  • 第五类,存储引擎型ParquetORC,主要用于大数据列式存储。

  • 选什么取决于业务需求:对内 RPC 用 Protobuf/Thrift,对外 API 用 JSON,嵌入式极致性能用 FlatBuffers,大数据分析用 Parquet。

  • 一张图总结:选型决策树

    你的数据要给谁看?
    ├── 人看 → 文本型
    │   ├── API 接口 → JSON
    │   ├── 配置文件 → YAML / TOML
    │   └── 企业级 → XML
    │
    └── 机器看 → 二进制
        ├── 需要极致解析速度(零拷贝)→ FlatBuffers / Cap'n Proto
        ├── 需要 RPC 通信(跨语言)
        │   ├── 标准统一 → Protobuf(gRPC)
        │   ├── 传输灵活 → Thrift
        │   └── Schema 动态演进 → Avro(Kafka)
        ├── 同语言进程内 → Kryo / gob / pickle
        └── 大数据分析 → Parquet / ORC
    
  • 序列化从"慢到快"的本质演进:

    • "序列化技术的发展,本质是在人类可读性机器效率之间不断向后者倾斜。JSON/XML 为人而生,Protobuf/Thrift 为机器而生,FlatBuffers/Cap'n Proto 为极致吞吐而生。没有最好,只有最合适。 选型要看场景:对外要灵活用 JSON,对内要性能用 Protobuf,极致要吞吐用 FlatBuffers。"
posted @ 2026-07-17 18:47  deyang  阅读(4)  评论(0)    收藏  举报