`

protobuf与stream的简单比较

阅读更多
使用protobuf与传统的stream作比较
1.协议模型:
package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "RoleTest";
message Role {
	optional int64 id = 1;	
  optional string name = 2;
  optional string email = 3;
}


即此协议包括id name email三个字段。

2.write写法比较
protobuf的写法如下
	public static byte[] protobufEncode() throws Exception{
		Builder builder = Role.newBuilder();
		builder.setId(id);
		builder.setName(name);
		builder.setEmail(mail);
		Role build = builder.build();
		byte[] byteArray = build.toByteArray();
		return byteArray;
	}



stream的写法如下
	public static byte[] streamEncode() throws Exception{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DataOutputStream output = new DataOutputStream(bos);
		output.writeLong(id);
		output.writeUTF(name);
		output.writeUTF(mail);
		byte[] bytes = bos.toByteArray();
		return bytes;
	}	



可以看出protobuf是不用在代码体现按照顺序write,而stream则需要。

3.read的写法比较

protobuf的写法如下
	public static void protobufDecode(byte[] data) throws Exception{
		Role role = Role.parseFrom(data);
		System.err.println(role.getId()+",name:"+role.getName()+",email:"+role.getEmail());
	}



stream的写法如下
	public static void streamDecode(byte[] data) throws IOException{
		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		DataInputStream input = new DataInputStream(bis);
		long id = input.readLong();
		String name = input.readUTF();
		String email = input.readUTF();
		System.err.println(id+",name:"+name+",email:"+email);
	}



跟write一样,protobuf是不用按照顺序读,直接可以转换成一个对象。

4.write的特殊情况
有一些协议的第一个字段是表示结果(如回复添加好友)。在操作验证失败的情况下,一般客户端会
提示一些语句,如'此玩家已经是您的好友'。这种操作失败的协议通常除第一个字段以后的字段(好友id、名字、性别等)都是
可以忽略的,但是用普通的stream方式去read,一定要完整读完,否则会抛异常。
而protobuf则可以在定义协议的时候使用optional关键字表示此字段是可以不发送的,所以用protobuf,可以这样写

	public static byte[] protobufEncode() throws Exception{
		Builder builder = Role.newBuilder();
		builder.setId(id);
		//builder.setName(name);
		//builder.setEmail(mail);
		Role build = builder.build();
		byte[] byteArray = build.toByteArray();
		return byteArray;
	}


读取的时候能够正常转换成对象,而没发送的字段按照字段类型的默认值来表示,如string默认是'',boolean是false,int32是0

5.流量对比
protobuf在压缩成byte[]的时候会动态计算字段的大小,但是会占用位,具体未看明白,看比较。
A.只发送整形的对比
用long型id,为以下情况

id:1
stream,len:8
[0, 0, 0, 0, 0, 0, 0, 1]
protobuf,len:2
[16, 1]

id:1000
stream,len:8
[0, 0, 0, 0, 0, 0, 3, -24]
protobuf,len:3
[16, -24, 7]

id:1000000
stream,len:8
[0, 0, 0, 0, 0, 15, 66, 64]
protobuf,len:4
[16, -64, -124, 61]

id:10000000000
stream,len:8
[0, 0, 0, 2, 84, 11, -28, 0]
protobuf,len:6
[16, -128, -56, -81, -96, 37]

id:10000000000000
stream,len:8
[0, 0, 9, 24, 78, 114, -96, 0]
protobuf,len:8
[16, -128, -64, -54, -13, -124, -93, 2]

id:1000000000000000
stream,len:8
[0, 3, -115, 126, -92, -58, -128, 0]
protobuf,len:9
[16, -128, -128, -102, -90, -22, -81, -29, 1]

id:100000000000000000
stream,len:8
[1, 99, 69, 120, 93, -118, 0, 0]
protobuf,len:10
[16, -128, -128, -88, -20, -123, -81, -47, -79, 1]

可以看出,当id数值小的时候,protobuf会比stream好,当数值到一定时,两者相同,当数值很大,protobuf会比stream差。

B.只发送字符串

name:k
stream,len:3
[0, 1, 107]
protobuf,len:3
[10, 1, 107]


name:kyle
stream,len:6
[0, 4, 107, 121, 108, 101]
protobuf,len:6
[10, 4, 107, 121, 108, 101]

name:kylekyle
stream,len:10
[0, 8, 107, 121, 108, 101, 107, 121, 108, 101]
protobuf,len:10
[10, 8, 107, 121, 108, 101, 107, 121, 108, 101]

name:kylekylekyle
stream,len:14
[0, 12, 107, 121, 108, 101, 107, 121, 108, 101, 107, 121, 108, 101]
protobuf,len:14
[10, 12, 107, 121, 108, 101, 107, 121, 108, 101, 107, 121, 108, 101]

可以看出,发送字符串是差不多的。


6.性能对比
发送id name email,作不同次数的读写循环对比,id选取两者流量相同10000000000000

id:10000000000000,name:kyle,email:kyle@qq.com
loop times:100
stream,spend:2 ms
protobuf,spend:30 ms

id:10000000000000,name:kyle,email:kyle@qq.com
loop times:10000
stream,spend:33 ms
protobuf,spend:81 ms

id:10000000000000,name:kyle,email:kyle@qq.com
loop times:100000
stream,spend:176 ms
protobuf,spend:178 ms

id:10000000000000,name:kyle,email:kyle@qq.com
loop times:1000000
stream,spend:1590 ms
protobuf,spend:1179 ms

比较奇怪,当循环数比较小时,stream领先,当循环数比较大时,protobuf领先
分享到:
评论

相关推荐

    protobuf-net简单实例

    7. **与其他序列化库的比较** - 与XML和JSON相比,protobuf-net的序列化结果通常更小,传输和解析速度更快。 - 相较于BinaryFormatter,protobuf-net提供跨平台兼容性,且序列化的数据格式更加紧凑。 8. **总结**...

    protobuf 3.11版本,静态编译

    protobuf是Protocol Buffers的简称,它是Google开发的一种数据序列化协议,用于结构化数据的序列化,类似于XML、JSON,但更小、更快、更简单。protobuf 3.11版本是一个稳定且广泛使用的版本,提供了许多改进和新特性...

    Unity与Netty进行ProtoBuf通信__

    ProtoBuf-net是.NET平台上对ProtoBuf的实现,它提供了一种简单且高效的方式来序列化和反序列化.NET对象,适用于Unity环境。 Netty则是一个高性能、异步的Java网络应用框架,常用于服务器端开发,提供了高度定制化的...

    protobuf-3.8.0 VS2019 C++使用案例

    总的来说,protobuf-3.8.0在VS2019中的使用涉及到.proto文件的编写、protoc编译器的调用、生成源代码的集成以及C++代码的编写与执行。这使得数据序列化变得简单,便于在网络通信、数据存储和跨平台项目中使用。

    Protobuf-net

    4. **易于使用**:protobuf-net提供了直观的API,可以轻松地将数据模型与protobuf消息类型对应起来。 **protobuf-net的使用步骤:** 1. **定义数据模型**:使用.proto文件定义数据结构,类似于接口或者类的声明。...

    protobuf-net网络协议的定制

    在Unity工程中,我们同样引入protobuf-net库,但需要考虑与C#服务器的交互。Unity支持异步网络操作,我们可以通过Unity的`UnityWebRequest`或`NetworkTransport`组件发送和接收数据。当收到服务器返回的数据时,使用...

    protobuf-net

    在跨语言通信中,如C#与Java,protobuf提供了一个标准的接口,使得不同平台和语言之间的数据交换变得简单。Java端也可以使用Google的官方protobuf库,两者通过protobuf定义的.proto文件进行通信协议的约定。 总的来...

    C#中使用二进制和ProtoBuf分别进行序列化、反序列化、压缩、解压缩对比测试示例源码.zip

    1. **序列化与反序列化**:创建一个对象实例,然后使用BinaryFormatter和ProtoBuf的相应方法进行序列化和反序列化。注意,ProtoBuf需要定义数据结构的.proto文件,并通过编译工具生成对应的C#类。 2. **压缩与解...

    基于Protobuf C++ serialize到char*的实现方法分析

    这种方法简单直接,但需要注意内存管理,确保在使用完后释放内存。 ### 方法三:使用`std::ostringstream`和`string::c_str()` 另一种方法是使用`std::ostringstream`将protobuf消息序列化为字符串,然后通过`...

    如何为asp.net core添加protobuf支持详解

    为了测试 protobuf 支持是否正常工作,我们可以创建一个简单的 DTO 类(Data Transfer Object),并使用 `ProtoContract` 和 `ProtoMember` 属性标记需要序列化的成员。例如: ```csharp [ProtoContract] public ...

    pb压缩代码

    以下是一个简单的示例,展示如何在C++中使用protobuf和zlib进行数据压缩和解压缩: ```cpp #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/...

    云风pbc windows下xx.proto生成xx.pb 工具

    #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/text_format.h> Person person; google::protobuf::TextFormat::...

    android gRPC 简单使用(csdn)————程序.pdf

    Logger.e("Stream", "onNext"); } // ... }); ``` gRPC 提供了一种高效、灵活的方式来实现分布式系统的通信。通过使用 Protocol Buffer 定义服务接口,生成客户端代码,并使用 gRPC 客户端调用服务端的方法,...

    GRPC原理解析

    GRPC的核心设计理念是使分布式系统中的服务间通信变得简单、高效且安全。 1. Protocol Buffers(protobuf) Protocol Buffers是Google开发的一种数据序列化协议,用于结构化数据的编码和解码。相比XML或JSON,...

    golang_grpc.zip

    例如,`grpc.NewServer` 用于创建服务器实例,`grpc.RegisterService` 注册服务,`grpc.Dial` 连接到 gRPC 服务器,`clientConn.NewStream` 创建一个双向流用于异步通信等。 **最佳实践**: - 使用版本管理工具(如...

    Go-使用grpcgo和python的双向流式RPC的快速演示

    12. **测试与调试**:在完成服务端和客户端的实现后,可以通过gRPC的测试工具进行交互测试,如使用`grpcurl`或编写简单的测试脚本。 本项目的压缩包"grpc-streaming-demo-master"可能包含了Go和Python的源代码示例...

    GRPC 四种模式(官方的demo)

    在GRPC中,服务端和客户端之间的交互主要有四种模式:简单请求(Unary Call)、服务器流(Server Streaming)、客户端流(Client Streaming)以及双向流(Bidirectional Streaming)。下面我们将详细探讨这四种模式...

    一种简单的可扩展的序列化方法(C++)

    这里,我们讨论的是一种基于C++实现的简单且可扩展的序列化方法,其灵感来源于Google的Protocol Buffers(protobuf)。 首先,`WHBSerial.h`可能包含了序列化接口的定义,它提供了基础的序列化和反序列化操作。这个...

    rpc原理的简单实现

    这里给出一个简单的RPC实现示例,使用Python的socket库: ```python # 服务器端 import socket def remote_service(data): return "Service result: " + data s = socket.socket(socket.AF_INET, socket.SOCK_...

Global site tag (gtag.js) - Google Analytics