Protobuf vs JSON

protobuf,vs,json · 浏览次数 : 104

小编点评

**作者: mengbinblog** **项目: mengbinGithub** **文件: 恋水无意.go** **内容:** ```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) } ``` **排版:** ``` 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) } ```

正文

Protobuf(Protocol Buffers)和 JSON 都是数据序列化格式,但它们在许多方面有着显著的不同。以下是对两者的一些主要比较:

  1. 数据大小和速度:
    • Protobuf:由于 Protobuf 是二进制格式,因此它生成的数据通常比 JSON 小很多,这使得 Protobuf 在网络传输中更加高效。同时,Protobuf 的解析和序列化速度也比 JSON 快。
    • JSON:JSON 是文本格式,它生成的数据通常比 Protobuf 大,且解析和序列化速度较慢。
  2. 可读性和易用性:
    • Protobuf:Protobuf 是二进制格式,人类无法直接阅读。此外,使用 Protobuf 需要预先定义数据结构(.proto 文件),这增加了使用的复杂性。
    • JSON:JSON 是文本格式,人类可以直接阅读和编辑。此外,JSON 的数据结构可以在运行时动态定义,这使得 JSON 更易于使用。
  3. 类型安全和版本兼容性:
    • Protobuf:Protobuf 支持静态类型检查,这可以在编译时捕获类型错误。此外,Protobuf 设计了一套版本兼容性机制,可以在不破坏旧版本的情况下添加新的字段。
    • JSON:JSON 是动态类型的,无法在编译时捕获类型错误。此外,JSON 没有内置的版本兼容性机制,如果数据结构发生变化,可能需要修改代码以适应新的结构。
  4. 支持的语言:
    • Protobuf:Google 提供了多种语言的 Protobuf 库,包括 C++、Java、Python、Golang 等。
    • JSON:几乎所有的编程语言都支持 JSON。
  5. 学习成本:
    • Protobuf:Protobuf 的学习曲线相对较陡。你需要理解 Protobuf 的语法,学习如何编写 .proto 文件,并且需要了解如何使用 Protobuf 编译器生成代码。此外,你还需要理解 Protobuf 的版本兼容性规则。
    • JSON:JSON 的学习曲线相对较平。JSON 的语法非常简单,大多数人可以在很短的时间内掌握。此外,几乎所有的编程语言都内置了 JSON 的支持,你不需要安装任何额外的库就可以开始使用 JSON。
  6. 使用成本:
    • 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: 恋水无意


与Protobuf vs JSON相似的内容:

Protobuf vs JSON

Protobuf(Protocol Buffers)和 JSON 都是数据序列化格式,但它们在许多方面有着显著的不同。以下是对两者的一些主要比较: 1. 数据大小和速度: - Protobuf:由于 Protobuf 是二进制格式,因此它生成的数据通常比 JSON 小很多,这使得 Protobuf

安装、学习protobuf

Protobuf是什么? 类似于json的一种数据格式,独立于语言,而且是二进制方式,所以比json更快,而且还可以直接存储一些图、树 序列化和反序列化 持久化(存到磁盘硬盘)领域中,数据存到磁盘叫序列化,从磁盘读取出来叫反序列化 网络传输领域中,数据块转字符串叫序列化,对端把字符串解析为数据块叫反

protoBuf 实现客户端与服务端

转载请注明出处: 1.定义消息格式 在 src/main/proto 目录下创建 person.proto 文件,并定义消息格式,例如: syntax = "proto3"; package example; message Person { string name = 1; int32 age =

Protobuf中如何指定json tag

在 Protocol Buffers (protobuf) 中,可以使用特定的选项来指定生成的 JSON 标签。通过在消息定义中使用 `[(json_name)]` 选项,可以控制生成的 JSON 字段名称。这样可以确保 Protocol Buffers 和 JSON 之间的互操作性。 下面是一个示

GRPC与 ProtoBuf 的理解与总结

转载请注明出处: 1.GRPC 官网:https://www.grpc.io/ gRPC 官方文档中文版:http://doc.oschina.net/grpc RPC 框架的目标就是让远程服务调用更加简单、透明,其负责屏蔽底层的传输方式(TCP/UDP)、序列化方式(XML/Json)和通信细节。

在Protocol Buffers中导入当前目录中的.proto文件

在protobuf中导入当前目录中的`.proto`文件时,可以使用相对路径。相对路径是相对于当前`.proto`文件所在的目录来引用其他`.proto`文件。 假设有以下目录结构: ``` my_project/ |-- proto/ | |-- person.proto |-- main.pro

使用脚本收发 protobuf 协议数据

服务器使用二进制的 protobuf 协议,如何使用脚本模拟请求?答案是将它转成 json 再用 jq 处理,一起来看看吧~

Go with Protobuf

原文在这里。 本教程为 Go 程序员提供了使用Protocol buffer的基本介绍。 本教程使用proto3向 Go 程序员介绍如何使用 protobuf。通过创建一个简单的示例应用程序,它向你展示了如何: 在.proto中定义消息格式 使用protocol buffer编译器 使用Go pro

Win环境安装Protobuf 2.0 版本

转载请注明出处: 安装步骤 下载 protobuf-2.5.0.zip 与 protoc-2.5.0-win32.zip 下载链接 : https://github.com/protocolbuffers/protobuf/releases/tag/v2.5.0 将protoc-2.5.0-win3

Protocol Buffer命名空间冲突

原文在[这里](https://protobuf.dev/reference/go/faq/#namespace-conflict)。 ## 什么是Protocol Buffer命名空间冲突? 所有链接到Go二进制文件的Protocol Buffer声明都被插入到一个全局注册表中。 每个Protoc