Protobuf vs JSON
Protobuf(Protocol Buffers)和 JSON 都是数据序列化格式,但它们在许多方面有着显著的不同。以下是对两者的一些主要比较:
- 数据大小和速度:
- Protobuf:由于 Protobuf 是二进制格式,因此它生成的数据通常比 JSON 小很多,这使得 Protobuf 在网络传输中更加高效。同时,Protobuf 的解析和序列化速度也比 JSON 快。
- JSON:JSON 是文本格式,它生成的数据通常比 Protobuf 大,且解析和序列化速度较慢。
- 可读性和易用性:
- Protobuf:Protobuf 是二进制格式,人类无法直接阅读。此外,使用 Protobuf 需要预先定义数据结构(.proto 文件),这增加了使用的复杂性。
- JSON:JSON 是文本格式,人类可以直接阅读和编辑。此外,JSON 的数据结构可以在运行时动态定义,这使得 JSON 更易于使用。
- 类型安全和版本兼容性:
- Protobuf:Protobuf 支持静态类型检查,这可以在编译时捕获类型错误。此外,Protobuf 设计了一套版本兼容性机制,可以在不破坏旧版本的情况下添加新的字段。
- JSON:JSON 是动态类型的,无法在编译时捕获类型错误。此外,JSON 没有内置的版本兼容性机制,如果数据结构发生变化,可能需要修改代码以适应新的结构。
- 支持的语言:
- Protobuf:Google 提供了多种语言的 Protobuf 库,包括 C++、Java、Python、Golang 等。
- JSON:几乎所有的编程语言都支持 JSON。
- 学习成本:
- Protobuf:Protobuf 的学习曲线相对较陡。你需要理解 Protobuf 的语法,学习如何编写 .proto 文件,并且需要了解如何使用 Protobuf 编译器生成代码。此外,你还需要理解 Protobuf 的版本兼容性规则。
- JSON:JSON 的学习曲线相对较平。JSON 的语法非常简单,大多数人可以在很短的时间内掌握。此外,几乎所有的编程语言都内置了 JSON 的支持,你不需要安装任何额外的库就可以开始使用 JSON。
- 使用成本:
- Protobuf:Protobuf 的使用成本相对较高。首先,你需要为每个数据结构编写一个 .proto 文件,然后使用 Protobuf 编译器生成代码。此外,如果你的数据结构发生了变化,你需要更新 .proto 文件并重新生成代码。这些步骤都需要额外的时间和工作。
- JSON:JSON 的使用成本相对较低。你可以直接在代码中定义数据结构,无需任何额外的步骤。此外,如果你的数据结构发生了变化,你只需要更新你的代码,无需任何其他操作。
总的来说,Protobuf 和 JSON 各有优劣,适用于不同的场景。如果你需要高效的数据传输和严格的类型检查,那么 Protobuf 可能是一个好选择。如果你需要易于使用和人类可读的数据格式,那么 JSON 可能更适合你。
下面以一个简单的例子来对Protobuf和JSON运行效率进行简单对比。
定义proto文件
首先通过.proto
来定义所需的结构:
syntax = "proto3"; package pvsj.proto; option go_package = "./;proto"; import "google/protobuf/struct.proto"; message Base { string tx_hash = 1; int64 timestamp = 2; google.protobuf.Struct extra = 3; uint64 block_number = 4; int32 category = 5; } message CertGen { string id = 1; string issuer = 2; string name = 3; string number = 4; string seal_name = 5; string seal_number = 6; string sign_hash = 7; string date = 8; Base base = 9; }
然后通过protoc
生成响应的go代码。
Benchmark
main.go
内容如下:
package main import ( "encoding/json" "math/rand" "time" "github.com/bytedance/sonic" "github.com/google/uuid" pb "github.com/mengbin92/pvsj/proto" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" ) func init() { rand.New(rand.NewSource(time.Now().UnixNano())) uuid.SetRand(rand.New(rand.NewSource(time.Now().UnixNano()))) } func main() { } // 使用protobuf进行序列化和反序列化 func genProto(num int) { for i := 0; i < num; i++ { data := map[string]interface{}{ "name": uuid.NewString(), "age": rand.Int(), "score": rand.Float64(), } extra, _ := structpb.NewStruct(data) base := &pb.Base{ TxHash: uuid.NewString(), Timestamp: time.Now().Unix(), Extra: extra, BlockNumber: rand.Uint64(), Category: rand.Int31(), } gen := &pb.CertGen{ Id: uuid.NewString(), Issuer: uuid.NewString(), Name: uuid.NewString(), Number: uuid.NewString(), SealName: uuid.NewString(), SealNumber: uuid.NewString(), SignHash: uuid.NewString(), Date: time.Now().Format(time.DateTime), Base: base, } genBytes, _ := proto.Marshal(gen) proto.Unmarshal(genBytes, gen) } } // 使用sonic对json进行序列化和反序列化 func genJsonSonic(num int) { for i := 0; i < num; i++ { data := map[string]interface{}{ "name": uuid.NewString(), "age": rand.Int(), "score": rand.Float64(), } extra, _ := structpb.NewStruct(data) base := &pb.Base{ TxHash: uuid.NewString(), Timestamp: time.Now().Unix(), Extra: extra, BlockNumber: rand.Uint64(), Category: rand.Int31(), } gen := &pb.CertGen{ Id: uuid.NewString(), Issuer: uuid.NewString(), Name: uuid.NewString(), Number: uuid.NewString(), SealName: uuid.NewString(), SealNumber: uuid.NewString(), SignHash: uuid.NewString(), Date: time.Now().Format(time.DateTime), Base: base, } genBytes, _ := sonic.Marshal(gen) sonic.Unmarshal(genBytes, gen) } } // 使用标准库对json进行序列化和反序列化 func genJsonStd(num int) { for i := 0; i < num; i++ { data := map[string]interface{}{ "name": uuid.NewString(), "age": rand.Int(), "score": rand.Float64(), } extra, _ := structpb.NewStruct(data) base := &pb.Base{ TxHash: uuid.NewString(), Timestamp: time.Now().Unix(), Extra: extra, BlockNumber: rand.Uint64(), Category: rand.Int31(), } gen := &pb.CertGen{ Id: uuid.NewString(), Issuer: uuid.NewString(), Name: uuid.NewString(), Number: uuid.NewString(), SealName: uuid.NewString(), SealNumber: uuid.NewString(), SignHash: uuid.NewString(), Date: time.Now().Format(time.DateTime), Base: base, } genBytes, _ := json.Marshal(gen) json.Unmarshal(genBytes, gen) } }
bench_test.go
内容如下:
package main import ( "testing" ) func BenchmarkGenProto(b *testing.B) { genProto(b.N) } func BenchmarkGenJsonSonic(b *testing.B) { genJsonSonic(b.N) } func BenchmarkGenJsonStd(b *testing.B) { genJsonStd(b.N) }

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2019-08-13 Ceph块设备
2019-08-13 CentOS7安装Ceph