第1部分 messagepack说明
1.1messagepack的消息编码说明
为什么messagepack比json序列化使用的字节流更少, 可通过图1-1、图1-2有个直观的感觉。
图1- 1 messagepack与json的格式对比1
图1- 2 messagepack与json的格式对比2
messagepack的具体的消息格式如图1-3所示,messagepack的数据类型主要分类两类:固定长度类型和可变长度类型。
图1- 3 messagepack的消息格式
messagepack的具体类型信息表示如图1-4所示。
图1- 4 messagepack的类型信息
1.2 messagepack的序列化和反序列化方式
现在msgpack能支持基本的数据类型,支持list和map, 还支持自定义的数据类型。例子1, 序列化和反序列化一个javabean, 只要加上@MessagePackMessage的注解。
/** * 一个用于messagepack测试序列化和反序列的javabean * * @author jimmee */ @MessagePackMessage public class Person { /** 编号 */ public int id; /** 名字 */ public String name; /**身高*/ public double height; /** * 默认构造函数 */ public Person() { }
序列化直接调用MessagePack的pack方法;反序列化则调用对应的unpack方法。这两个方法,都支持传递序列化和反序列化的数据类型。
1.3 与json的序列化性能对比
如下所示,通过100条数据的序列化和反序列化进行对比。
List<Map> msgs = new ArrayList<Map>(); for (int i = 0; i < 100; i++) { Map msg = new HashMap(); msg.put(Const.FID, i); msg.put(Const.SUBJECT, "subject" + i); msg.put(Const.LABEL0, 1); msg.put(Const.FROM, "test@163.com"); msg.put(Const.TO, "test@126.com"); msg.put(Const.MODIFIED_DATE, new Date().getTime()); msg.put(Const.RECEIVED_DATE, new Date().getTime()); msg.put(Const.SENT_DATE, new Date().getTime()); msgs.add(msg); }
比较结果如表1-1所示。
表1- 1 messagepack与json的性能对比
框架 |
字节大小(byte) |
序列化时间(ns) |
反序列化时间(ns) |
messagepack |
12793 |
2313335 |
529458 |
json |
17181 |
1338371 |
1776519 |
可以看出,messagepack的序列化字节数比json小将近30%;序列化时间messagepack差不多是json的两倍;反序列化时间,messagepack只需要json的30%的时间。
但是,值得注意的是,虽然messagepack的反序列化时间比较少,但是要真正转换为前端需要的类型参数格式,还需要额外的一些时间。
第2部分 protocol buffers
2.1 protocol buffers的消息编码说明
Protocol Buffers支持的数据类型如下图所示:
图2- 1 protocol buffers支持的数据类型。
首先对Varint进行说明。Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。
比如对于 int32 类型的数字,一般需要 4 个 byte 来表示。但是采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。当然,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。
Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。因此小于 128 的数字都可以用一个 byte 表示。大于 128 的数字,比如 300,会用两个字节来表示:1010 1100 0000 0010。
图2-2说明了 Google Protocol Buffer 如何解析两个 bytes。注意到最终计算前将两个 byte 的位置相互交换过一次,这是因为 Google Protocol Buffer 字节序采用 little-endian 的方式。
图2- 2 protocol buffers解析两个字节
消息经过序列化后会成为一个二进制数据流,该流中的数据为一系列的 Key-Value 对,如图2-3所示。
图2- 3 protocol buffers的消息流
采用这种 Key-Pair 结构无需使用分隔符来分割不同的 Field。对于可选的 Field,如果消息中不存在该 field,那么在最终的 Message Buffer 中就没有该 field,这些特性都有助于节约消息本身的大小。
假设我们生成如下的一个消息Message:
Message.id = 5; Message.info = “hello”; |
则最终的 Message Buffer 中有两个 Key-Value 对,一个对应消息中的 id;另一个对应 info。
Key 用来标识具体的 field,在解包的时候,Protocol Buffer 根据 Key 就可以知道相应的 Value 应该对应于消息中的哪一个 field。
Key 的定义如下:
(field_number << 3) | wire_type |
可以看到 Key 由两部分组成。第一部分是 field_number。第二部分为 wire_type。表示 Value 的传输类型。
wire type如表2-1所示。
表2- 1 wire type说明
Type |
Meaning |
Used For |
0 |
Varint |
int32, int64, uint32, uint64, sint32, sint64, bool, enum |
1 |
64-bit |
fixed64, sfixed64, double |
2 |
Length-delimited |
string, bytes, embedded messages, packed repeated fields |
3 |
Start group |
Groups (deprecated) |
4 |
End group |
Groups (deprecated) |
5 |
32-bit |
fixed32, sfixed32, float |
在计算机内,一个负数一般会被表示为一个很大的整数,因为计算机定义负数的符号位为数字的最高位。如果采用 Varint 表示一个负数,那么一定需要 5 个 byte。为此 Google Protocol Buffer 定义了 sint32,sint64 类型,采用 zigzag 编码。
Zigzag 编码用无符号数来表示有符号数字,正数和负数交错,如图2-3所示。使用 zigzag 编码,绝对值小的数字,无论正负都可以采用较少的 byte 来表示,充分利用了 Varint 这种技术。
图2- 4 ZigZag编码
2.2 protocol buffers的序列化和反序列化
步骤:
创建消息的定义文件.proto;
使用protoc工具将proto文件转换为相应语言的源码;
使用类库支持的序列化和反序列化方法进行操作。
以同样的数据的操作为例:
1. 定义proto文件messages.ptoto
message MessageMeta { required int32 id = 1; required string subject = 2; optional int32 lablel0 = 3; required string from = 4; required string to = 5; optional int64 modifiedDate = 6; optional int64 receivedDate = 7; optional int64 sentDate = 8; }
message MessageMetas { repeated MessageMeta msg = 1; }
2. 将message.proto文件转换为java语言的源码
例如, 执行命令:protoc -I=src --java_out=out src/messages.proto产生Messages的java文件。
3. 执行序列化和反序列化
MessageMetas.Builder msgsBuilder = MessageMetas.newBuilder(); for (int i = 0; i < 100; i++) { MessageMeta.Builder msgBuilder = MessageMeta.newBuilder(); msgBuilder.setId(i); msgBuilder.setSubject("subject" + i); msgBuilder.setLablel0(1); msgBuilder.setFrom("test@163.com"); msgBuilder.setTo("test@126.com"); msgBuilder.setModifiedDate(new Date().getTime()); msgBuilder.setReceivedDate(new Date().getTime()); msgBuilder.setSentDate(new Date().getTime()); msgsBuilder.addMsg(msgBuilder.build()); } MessageMetas msgs = msgsBuilder.build();
之后调用相应的writeTo方法进行序列化, 调用parseFrom进行反序列化。
2.3 与json等的性能对比
表2- 2 性能对比表格
框架 |
字节大小(byte) |
序列化时间(ns) |
反序列化时间(ns) |
messagepack |
12793 |
2313335 |
529458 |
protocol buffers |
6590 |
941790 |
408571 |
json |
17181 |
1338371 |
1776519 |
可以看出,protocol buffers在字节流,序列化时间和反序列化时间方面都明显较优(即空间和时间上都比较好)。
第3部分 thrift
thrift的架构如图3-1所示。图3-1显示了创建server和client的stack。最上面的是IDL,然后生成Client和Processor。红色的是发送的数据。protocol和transport 是Thrift运行库的一部分。通过Thrift 你只需要关心服务的定义,而不需要关心protocol和transport。
Thrift支持 text 和 binary protocols,binary protocols要比text protocols,但是有时候 text protocols比较有用(例如:调试的时候)。支持的协议有:
TBinaryProtocol :直接的二进制格式
TCompactProtocol :效率和高压缩编码数据
TDenseProtocoal : 和TCompactProtocol相似,但是省略了meta信息,从哪里发送的,增加了receiver。还在实验中,java实现还不可用。
TJSONProtocoal:使用JSON
TSImpleJSONProtocoal :只写的protocol使用JSON。适合被脚本语言转化
TDebugProtocoal:使用人类可读的text 格式 帮助调试
图3- 1 thrift架构图
上面的protocol 说明了传送的是什么样的数据,Thrift 的transports 则说明了怎样传送这些数据。支持的transport:
TSocket :使用 blocking socket I/O;
TFramedTransport :以帧的形式发送,每帧前面是一个长度。要求服务器来non-blocking server;
TFileTransport :写到文件;
TMemoryTransport :使用内存 I/O ,java实现中在内部使用了ByteArrayOutputStream;
TZlibTransport 压缩 使用zlib,在java实现中还不可用。
最后,thrift 提供了servers:
TSimpleServer :单线程server,使用标准的blocking IO,用于测试;
TThreadPoolServer:多线程server ,使用标准的blocking IO;
TNonblockingServer 多线程 server,使用 non-blocking IO (java实现中使用了NIO channels),TFramedTransport必须使用在这个服务器。
一个server只允许定义一个接口服务。这样的话多个接口需要多个server。这样会带来资源的浪费。通常可以通过定义一个组合服务来解决。
3.1 thrift的消息编码说明
1. 支持的数据类型
所有编程语言中都可用的关键类型。
bool 布尔值,真或假
byte 有符号字节
i16 16位有符号整数
i32 32位有符号整数
i64 64位有符号整数
double 64位浮点数
string 与编码无关的文本或二进制字符串
可基于基本类型定义结构体,例如:
struct Example { 1:i32 number=10, 2:i64 bigNumber, 3:double decimals, 4:string name="thrifty" }
支持的容器有list<type>,set<type>和Map<type1,type2>。
若使用TCompactProtocol,传递的消息形式如图3-2所示:
图3- 2 thrift的compact方式的消息流
在这种方式下,对整数而言,也是采用可变长度的方式进行实现。一个字节,最高位表示是否还有数据,低7位是实际的数据,如图3-3所示, 整数106903的编码, 相比普通的int类型,节省一个字节。
图3- 3 compact方式对一个整数106903进行编码
3.2thrift的序列化和反序列化方式
步骤:
创建thrift接口定义文件;
将thrift的定义文件转换为对应语言的源代码;
选择相应的protocol,进行序列化和反序列化。
仍以同样的数据对象为例子:
定义thrift文件messages.thrift
struct MessageMeta { 1:i32 id; 2:string subject; 3:i32 lablel0; 4:string from; 5:string to; 6:i64 modifiedDate; 7:i64 receivedDate; 8:i64 sentDate; } struct MessageMetas { 1:list<MessageMeta> msgs; }
2. 将定义的文件转换成相应的java源码
执行命令:thrift -gen java messages.thrift
3. 执行序列化和反序列化
MessageMetas msgs = new MessageMetas(); List<MessageMeta> msgList = new ArrayList<MessageMeta>(); for (int i = 0; i < 100; i++) { MessageMeta msg = new MessageMeta(); msg.setId(i); msg.setSubject("subject" + i); msg.setLablel0(1); msg.setFrom("test@163.com"); msg.setTo("test@126.com"); msg.setModifiedDate(new Date().getTime()); msg.setReceivedDate(new Date().getTime()); msg.setSentDate(new Date().getTime()); msgList.add(msg); } msgs.setMsgs(msgList); // 序列化 ByteArrayOutputStream out = new ByteArrayOutputStream(); TTransport trans = new TIOStreamTransport(out); TBinaryProtocol tp = new TBinaryProtocol(trans); msgs.write(tp); byte [] buf = out.toByteArray(); // 反序列化 ByteArrayInputStream in = new ByteArrayInputStream(buf); trans = new TIOStreamTransport(in); tp = new TBinaryProtocol(trans); MessageMetas msgs2 = new MessageMetas(); msgs2.read(tp);
3.3与json等的性能对比
表3- 1 性能对比
框架 |
字节大小(byte) |
序列化时间(ns) |
反序列化时间(ns) |
messagepack |
12793 |
2313335 |
529458 |
protocol buffers |
6590 |
941790 |
408571 |
thrift |
6530 |
798696 |
754458 |
json |
17181 |
1338371 |
1776519 |
通过对比,可以发现thrift总的来说,都比较不错。
第4部分 小结
通过对messagepack,protocol buffers以及thrift的分析,主要分析了这些框架的序列化和反序列化部分的内容。实际上messagepack和thrift都还有自己的rpc调用框架。
所有的测试都是在本机上进行,基于100条元数据进行测试。可能不同数据,以及不同的规模,测试结果应该会存在差别,https://github.com/eishay/jvm-serializers/wiki/的有比较好的测试结果说明。根据自己的测试,从性能上说,messagepack,protocol buffers以及thrift都比json好(在测试时,发现messagepack序列化的时间稍微多一些)。
从编程语言上来说,messagepack,protocol buffers以及thrift,当然还包括json,都是支持跨语言的通讯的。
从接口定义的灵活性来(或者是否支持动态类型),messagepack较protocol buffers以及thrift较好,后两者都要预先定义schema并相对固定。
实际工作中, 一般都采用protocol buffers或者thrift.
第5部分 参考资料
2. http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/overview.html
3. http://jnb.ociweb.com/jnb/jnbJun2009.html
4. http://code.google.com/p/thrift-protobuf-compare/
5. http://www.tbdata.org/archives/1307
6. https://github.com/eishay/jvm-serializers/wiki/
7. http://wiki.apache.org/thrift/
8. http://pypi.python.org/pypi/msgpack-python/
相关推荐
5. **Apache Thrift**:另一种跨语言的序列化框架,它不仅提供序列化,还提供了服务接口定义和RPC框架。 6. **MessagePack**:轻量级的二进制序列化格式,比JSON更快更小,适合嵌入式设备和实时系统。 7. **设计...
1. **Google Protocol Buffers (protobuf)**:protobuf是Google开发的一种高效的数据序列化协议,支持C++、Java和Python等多种语言。它提供了强大的代码生成工具,可以将定义的.proto文件转换为结构化数据的存取代码...
在Java之外,还有许多其他序列化技术,如JSON、Hessian、XML、protobuf、kryo、MsgPack、FST、thrift和protostuff等,每种技术都有其独特的优点和适用场景。例如,protobuf提供了高效、紧凑的二进制编码,kryo提供了...
- **MessagePack**:提供JSON类似的二进制序列化库,适合高效数据交换。 - **protobuf (Protocol Buffers)**:Google的数据交换格式,支持C++和其他多种语言。 - **protobuf-c**:C语言的Protocol Buffers实现。 ...
Alibaba_Java_Coding_Guidelines-2.2.3.0x
【ABB机器人】-IRB460机器人维护信息V1.pdf
内容概要:本文详细介绍了新能源汽车VCU(车辆控制单元)控制器的开源项目,涵盖从应用层代码到底层代码、原理图、PCB设计、通信协议及控制策略等多个方面。应用层代码展示了如何根据电池电量调整车辆行驶模式,底层代码涉及硬件驱动如GPIO控制和ADC采样配置。硬件设计部分包括详细的原理图和PCB布局,确保系统的稳定性和可靠性。通信协议采用CAN网络,确保数据可靠传输,控制策略则涵盖了能量回收、扭矩控制等关键技术。丰富的文档资料和测试用例为开发人员提供了宝贵的学习和开发资源。 适合人群:新能源汽车开发人员、硬件工程师、嵌入式软件工程师、学生及研究人员。 使用场景及目标:帮助开发人员深入了解新能源汽车VCU控制器的工作原理和技术细节,加速项目开发进程,降低开发难度。无论是初学者还是有经验的专业人士,都可以从中受益。 其他说明:该项目不仅提供了完整的源代码和硬件设计文件,还包括详细的测试用例和故障处理方案,使得VCU开发变得更加透明和可复现。
详解DeepSeek的十个安全问题.pdf
《网络传播技术与实务》第10章-握在手中的网络——移动通信与无线网络技术.ppt
《计算机专业英语》chapter9-Communication-by-Avatars.ppt
性能测试工具Xrunner的使用手册
内容概要:本文深入探讨了基于自抗扰控制(ADRC)的永磁同步电机(PMSM)矢量控制调速系统的仿真方法及其优势。首先介绍了模型搭建,包括DC直流电压源、三相逆变器、永磁同步电机、采样模块、Clark、Park、Ipark以及SVPWM等关键组件。接着详细解析了ADRC在电流环和转速环中的应用,展示了其通过扩张状态观测器(ESO)实现的高精度扰动观测与补偿机制。文中还提供了部分MATLAB代码示例,如SVPWM模块和ADRC控制器的具体实现。仿真结果显示,ADRC相比传统PI控制器,在突加负载时表现出更好的稳定性和更快的响应速度,且不存在积分饱和问题。此外,文章讨论了一些实际应用中的注意事项和技术挑战。 适合人群:从事电机控制领域的研究人员、工程师及高校相关专业师生。 使用场景及目标:适用于希望深入了解和掌握现代先进电机控制技术的研究人员和工程师。目标是通过仿真平台验证ADRC的有效性,并为实际工程项目提供理论支持和技术指导。 其他说明:尽管ADRC具有诸多优点,但在实际应用中仍需注意参数选择和硬件条件限制等问题。
《网络设备安装与调试(锐捷版)》项目1-配置交换机设备-优化网络传输.pptx
内容概要:本文详细介绍了如何使用Fortran语言在ABAQUS中开发UMAT(用户材料子程序)和VUMAT(显式用户材料子程序),以实现材料损伤断裂弹塑性的自定义建模。文章首先阐述了材料损伤断裂弹塑性的重要性和应用场景,强调了自定义材料子程序在处理复杂材料行为方面的优势。接着,分别展示了UMAT和VUMAT的基本代码结构及其核心计算步骤,如材料参数读取、弹性刚度矩阵初始化、塑性应变增量计算以及应力更新等。此外,还讨论了DISP模型的应用,提供了具体的损伤演化和应力折减方法,并分享了一些实用的调试技巧和注意事项。 适合人群:具备一定ABAQUS使用经验和Fortran编程基础的研究人员和技术人员,尤其是从事材料力学、结构工程等领域的工作人士。 使用场景及目标:适用于需要对特定材料进行精确建模的工程项目,如航空航天、土木建筑等。通过自定义UMAT和VUMAT子程序,能够更好地模拟材料在复杂载荷条件下的损伤演化与断裂过程,提高结构安全性和可靠性评估的准确性。 其他说明:文中不仅提供了详细的代码示例,还分享了许多实践经验,帮助开发者避免常见错误并优化性能。同时提醒读者关注材料参数的正确配置、雅可比矩阵的对称性等问题,确保计算稳定可靠。
V1_3_example.ipynb
安川机器人DX100操作要领书 通用-搬运用途-E.0.pdf
这个是完整源码 SpringBoot + vue 实现 【java毕业设计】SpringBoot+Vue图书馆(图书借阅)管理系统 源码+sql脚本+论文 完整版 数据库是mysql 随着社会的发展,计算机的优势和普及使得阿博图书馆管理系统的开发成为必需。阿博图书馆管理系统主要是借助计算机,通过对图书借阅等信息进行管理。减少管理员的工作,作,同时也方便广大用户对所需图书借阅信息的及时查询以及管理。 阿博图书馆管理系统的开发过程中,采用B / S架构,主要使用Java技术进行开发,结合最新流行的springboot框架。使用Mysql数据库和Eclipse开发环境。该阿博图书馆馆管理系统的开发过程中,采用B / S架构,主要使用Java技术进行开发,结合最新流行的spri管理系统包括用户和管理员。其主要功能包括管理员:首页、个人中心、用户管理、图书分类管理、图书信息管理、图书借阅管理、图书归还管理、缴纳罚金管理、留言板管理、系同时也方便广大用户对所需图书借阅信息的及时查询以及管理。 阿博图书馆管理系统的开发过程中,采用B / S架构,主要使用Java技术进行开发,结合最新流行的springboot框架。使用Mysql数据库和Eclipse开发环境。该阿博图书馆管理系统包括用户和管理员。其主要功能包括管理员:首页、个人中心、用户管理、图书分类管理、图书信息管理、图书借阅管理、图书归还管理、缴纳罚金管理、留言板管理、系统管理,用户:首页、个人中心、图书借阅管理、图书归还管理、缴纳罚金管理、我的收藏管理,前台首页;首页、图书信息、公告信息、留言反馈、个人中心、后台管理等功能。 本论文对阿博图书馆管理系统的发展背景进行详细的介绍,并且对系统开发技术进行介绍,然后对系统进行需求分析,对阿博图书馆管理系统业务流程、系统结构以及数据都进行详细说明。用户可根据关键字进行查找自己想要的信息等。
内容概要:本文详细介绍了一个基于YALMIP和MATLAB的微电网优化调度模型,旨在帮助新手理解和应用微电网优化调度的基本概念和技术。模型综合考虑了蓄电池管理、市场购电售电约束以及功率平衡等因素,以实现系统总费用最低为目标。文中提供了详细的MATLAB代码示例,涵盖变量定义、约束条件建立、目标函数设定及优化求解过程,并附带了调试建议和可视化方法。此外,还讨论了一些常见的错误及其解决办法,如充放电互斥约束、功率平衡约束等。 适合人群:对微电网优化调度感兴趣的初学者,尤其是有一定MATLAB基础的学生或研究人员。 使用场景及目标:适用于希望快速掌握微电网优化调度基本原理的学习者,通过动手实践加深对相关理论的理解。具体应用场景包括但不限于:学术研究、课程作业、个人兴趣项目等。 其他说明:该模型不仅有助于理解微电网的工作机制,还可以为进一步探索复杂的微电网优化问题奠定坚实的基础。
内容概要:本文详细介绍了如何利用MATLAB搭建卷积神经网络(CNN),用于处理具有10个输入特征和3个输出变量的数据预测任务。首先进行数据预处理,包括数据读取、归一化以及训练集和测试集的划分。接着设计了一个包含多个卷积层、批量归一化层、ReLU激活函数层和全连接层的网络架构,确保能够有效提取特征并完成多输出预测。训练过程中采用Adam优化算法,并设置了合理的超参数如最大迭代次数、批次大小和初始学习率等。最终通过预测和反归一化步骤得到模型性能评价指标MAE和R²,展示了良好的预测效果。 适合人群:具有一定MATLAB编程基础和技术背景的研究人员或工程师,尤其是那些从事数据分析、机器学习领域的专业人士。 使用场景及目标:适用于需要解决多输入多输出预测问题的实际项目中,比如工业生产过程监控、设备故障诊断等领域。目的是帮助用户掌握使用MATLAB实现CNN的方法论,从而提高工作效率和解决问题的能力。 其他说明:文中提供了完整的代码片段供读者参考实践,同时针对可能出现的问题给出了实用性的建议,如调整批量大小、降低学习率等方法来应对训练不稳定的情况。此外还提到了一些改进方向,例如改变卷积核尺寸或者引入空洞卷积以增强模型表现。
机器人概要(外形图、目录的阅读方法)20120428.ppt