Protobuf与JAVA

如何在Java中使用protobuf 是一种数据格式,同json,xml,等。但是一种二进制数据格式。 阅读详情

    我们在开发一些RPC调用的程序时,通常会涉及到对象的序列化/反序列化的问题,比如一个“Person”对象从Client端通过TCP方式发送到Server端;因为TCP协议(UDP等这种低级协议)只能发送字节流,所以需要应用层将Java对象序列化成字节流,数据接收端再反序列化成Java对象即可。“序列化”一定会涉及到编码(encoding,format),目前我们可选择的编码方式:

    1)使用JSON,将java对象转换成JSON结构化字符串。在web应用、移动开发方面等,基于Http协议下,这是常用的,因为JSON的可读性较强。性能稍差。

    2)基于XML,和JSON一样,数据在序列化成字节流之前,都转换成字符串。可读性强,性能差,异构系统、open api类型的应用中常用。

    3)使用JAVA内置的编码和序列化机制,可移植性强,性能稍差。无法跨平台(语言)。

    4)其他开源的序列化/反序列化框架,比如Apache Avro,Apache Thrift,这两个框架和Protobuf相比,性能非常接近,而且设计原理如出一辙;其中Avro在大数据存储(RPC数据交换,本地存储)时比较常用;Thrift的亮点在于内置了RPC机制,所以在开发一些RPC交互式应用时,Client和Server端的开发与部署都非常简单。

 

    评价一个序列化框架的优缺点,大概有2个方面:1)结果数据大小,原则上说,序列化后的数据尺寸越小,传输效率越高。 2)结构复杂度,这会影响序列化/反序列化的效率,结构越复杂,越耗时。

 

    Protobuf是一个高性能、易扩展的序列化框架,它的性能测试有关数据可以参看官方文档。通常在TCP Socket通讯(RPC调用)相关的应用中使用;它本身非常简单,易于开发,而且结合Netty框架可以非常便捷的实现一个RPC应用程序,同时Netty也为Protobuf解决了有关Socket通讯中“半包、粘包”等问题(反序列化时,字节成帧)。

 

1、安装Protobuf

    从“https://developers.google.com/protocol-buffers/docs/downloads”下载安装包,windows下的使用不再赘言;在linux或者mac下,下载tar.gz的压缩包,解压后执行:

$ ./configure
$ make
$ make check
$ make install

 

    此后,可以通过“protoc --version”查看是否安装成功了,安装过程不需要配置环境变量。安装主要是为了能够使用命令编译proto文件,实际部署环境并不需要。

 

2、样例

    Protobuf需要一个schema声明文件,后缀为“.proto”的文本文件,内容样例如下:

option java_package = "com.test.protobuf";
option java_outer_classname="PersonProtos";

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

 

    如果你曾经使用过thrift、avro,你会发现它们都需要一个类似的schema文件,只是结构规则不同罢了。特别备注:protbuf和thrift的声明文件相似度极高。

    “message”表示,声明一个“类”,即java中的class。message中可以内嵌message,就像java的内部类一样。一个message有多个filed,“required string name = 1”则表示:name字段在序列化、反序列化时为第一个字段,string类型,“required”表示这个字段的值是必选;可以看出每个filed都至少有着三个部分组成,其中filed的“位置index”全局唯一。“optional”表示这个filed是可选的(允许为null)。“repeated”表示这个filed是一个集合(list)。也可以通过[default = ]为一个“optional”的filed指定默认值。

 

    我们可以在一个.proto文件中声明多个“message”,不过大部分情况下我们把互相继承或者依赖的类写入一个.proto文件,将那些没有关联关系的类分别写入不同的文件,这样便于管理。

 

 

    我们可以在.proto文件的头部声明一些额外的信息,比如“java_package”表示当“generate code”时将生成的java代码放入指定的package中。“java_outer_classname”表示生成的java类的名称。

 

    然后执行如下命令,生成JAVA代码:

protoc --java_out=./ Persion.proto

 

    通过“--java_out”指定生成JAVA代码保存的目录,后面紧跟“.proto”文件的路径。此后我们看到生成 了Package和一个PersonProto.java文件,我们只需要把此java文件复制到项目中即可。

 

3、JAVA实例

    1)pom.xml

<dependency>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-java</artifactId>
     <version>2.6.1</version>
</dependency>

 

    2)测试:

        PersonProtos.Person.Builder personBuilder = PersonProtos.Person.newBuilder();
        personBuilder.setEmail("test@gmail.com");
        personBuilder.setId(1000);
        PersonProtos.Person.PhoneNumber.Builder phone = PersonProtos.Person.PhoneNumber.newBuilder();
        phone.setNumber("18610000000");

        personBuilder.setName("张三");
        personBuilder.addPhones(phone);

        PersonProtos.Person person = personBuilder.build();

 

    获得到person实例后,我们可以通过如下方式,将person对象序列化、反序列化。

        //第一种方式
        //序列化
        byte[] data = person.toByteArray();//获取字节数组,适用于SOCKET或者保存在磁盘。
        //反序列化
        PersonProtos.Person result = PersonProtos.Person.parseFrom(data);
        System.out.println(result.getEmail());

    

   这种方式,适用于很多场景,Protobuf会根据自己的encoding方式,将JAVA对象序列化成字节数组。同时Protobuf也可以从字节数组中重新decoding,得到Java新的实例。

        //第二种序列化:粘包,将一个或者多个protobuf对象字节写入stream。
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        //生成一个由:[字节长度][字节数据]组成的package。特别适合RPC场景
        person.writeDelimitedTo(byteArrayOutputStream);
        //反序列化,从steam中读取一个或者多个protobuf字节对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        result = PersonProtos.Person.parseDelimitedFrom(byteArrayInputStream);
        System.out.println(result.getEmail());

 

    第二种方式,是RPC调用中、Socket传输时适用,在序列化的字节数组之前,添加一个varint32的数字表示字节数组的长度;那么在反序列化时,可以通过先读取varint,然后再依次读取此长度的字节;这种方式有效的解决了socket传输时如何“拆包”“封包”的问题。在Netty中,适用了同样的技巧。

 

        //第三种序列化,写入文件或者Socket
        FileOutputStream fileOutputStream = new FileOutputStream(new File("/test.dt"));
        person.writeTo(fileOutputStream);
        fileOutputStream.close();

        FileInputStream fileInputStream = new FileInputStream(new File("/test.dt"));
        result = PersonProtos.Person.parseFrom(fileInputStream);
        System.out.println(result);

 

    第三种方式,比较少用。但是比较通用,意思为将序列化的字节数组写入到OutputStream中,具体的拆包工作,交给了高层框架。

 

4、protobuf入门介绍

    以上述Person.proto文件为例:

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
}

 

    声明了三个filed,每个filed都“规则”、“类型”、“字段名称”和一个“唯一的数字tag”。

    1)其中“规则”可以为如下几个值:

    “required”:表示此字段值必填,一个结构良好的message至少有一个flied为“required”。

    “optional”:表示此字段值为可选的。对于此类型的字段,可以通过default来指定默认值,这是一个良好的设计习惯。

    

optional int32 page = 3 [default = 10];
 

 

    如果没有指定默认值,在encoding时protobuf将会用一个特殊的默认值来替代。对于string,默认值为空,bool类型默认为false,数字类型默认位0,对于enum则默认值为枚举列表的第一个值。

 

    “repeated”:表示这个字段的值可以允许被重复多次,如果转换成JAVA代码,此filed数据结构为list,有序的。可以在“repeated”类型的filed后使用“packed”--压缩,提高数据传输的效率。

 

repeated int32 numbers = 4 [packed=true];
 

 

    特别需要注意:当你指定一个filed位required时,需要慎重考虑这个filed是否永远都是“必须的”。将一个required调整为optional,需要同时重新部署数据通讯的Client和Server端,否则将会对解析带来问题。

 

    2)可以在一个.proto文件中,同时声明多个message,这样是允许的。

    3)为message或者filed添加注释,风格和JAVA一样:

 

optional int32 page = 3;// Which page number do we want?
 

 

    4)数据类型与JAVA对应关系:

protobufjava
doubledouble
floatfloat
int32int
int64long
boolboolean
stringString
bytesByteString

 

    其中“ByteString”是Protobuf自定义的JAVA API。

 

     5)枚举:和JAVA中Enum API一致,如果开发者希望某个filed的值只能在一些限定的列表中,可以将次filed声明为enum类型。Protobuf中,enum类型的每个值是一个int32的数字,不像JAVA中那样enum可以定义的非常复杂。如果enum中有些值是相同的,可以将“allow_alias”设定为true。

message Person {
  required Type type = 1;
  
  enum Type {
  option allow_alias = true;
    TEACHER = 0;
    STUDENT = 1;
    OTHER = 1;//the same as STUDENT
  }
}

 

     6)import:如果当前.proto文件中引用了其他proto文件的message类型,那么可以在此文件的开头声明import。

import "other_protos.proto";

 

    不过这会引入一个小小的麻烦,如果你的“other_protos.proto”文件变更了目录,需要连带修改其他文件。

 

    7)嵌入message:类似于java的内部类,即在message中,嵌入其他message。如Person.proto例子中的PhoneNumber。

 

    8)更新message类型:如果一个现有的message类型无法满足当前的需要,比如你需要新增一个filed,但是仍然希望使用生成的旧代码来解析。

        (1)不要修改现有fileds的数字tag,即字段的index数字。

        (2)新增字段必须为optional或者repeated类型,同时还要为它们设置“default”值,这意味着“old”代码序列化的messages能够被“new”代码解析。“new”代码生成的数据也能被“old”代码解析,对于“old”代码而言,那些没有被声明的filed将会在解析式忽略。

        (3)非“required”filed可以被删除,但是它的“数字tag”不能被其他字段重用。

        (4)int32、uint32、int64、uint64、bool,是互相兼容的,它们可以从一个类型修改成另外一个,而不会对程序带来错误。参见源码WireFormat.FiledType

        (5)sint32和sint64是兼容的,但和其他数字类型是不兼容的。

        (6)string和bytes是兼容的,只要为UTF-8编码的。注意protobuf中string默认是UTF-8编码的。

        (7)optional与repeated是兼容的。如果输入的数据格式是repeated,但是client希望接受的数据是optional,对于原生类型,那么client将会使用repeated的最后一个值,对于message类型,client将会merge这些输入的数据。

        (8)修改“default”值通常不会有任何问题,只要保证这个默认值不会被真正的使用。

 

    9)Map结构:

map<key_type, value_type> map = 3;

 

    其中key_type可以为任何“整形”或者string类型,value_type可以为任意类型,只要JAVA API能够支持。map类型不能被“repeated”、“optional”或者“required”修饰,传输过程中无法确保map中数据的顺序,

对于文本格式,map是按照key排序。

 

    10)如下为一些有用的选项:

        (1)java_package:在.proto文件的顶部设定,指定生成JAVA文件时类所在的package。

option java_package = "com.example.foo";

 

        (2)java_outer_classname:在.proto文件的顶部设定,指定生成JAVA文件时类的名字。一个.proto文件只会生成一个JAVA类。

option java_outer_classname = "FooProtos";

 

        (3)packed:对于repeated类型有效,指定输入的数据是否“压缩”。

 

5、protobuf序列化原理:

    其实protobuf的序列化原理并不是什么高超的“绝技”:如果你曾经了解过thrift、avro,或者从事过socket通信,那么你对protobuf的序列化方式并不感到惊奇;如下为protobuf的序列化format:

 

    [serializedSize]{[int32(tag,type)][value]...}

 

 

    对于一个message,序列化时首先就算这个message所有filed序列化需要占用的字节长度,计算这个长度是非常简单的,因为protobuf中每种类型的filed所占用的字节数是已知的(bytes、string除外),只需要累加即可。这个长度就是serializedSize,32为integer,在protobuf的某些序列化方式中可能使用varint32(一个压缩的、根据数字区间,使用不同字节长度的int);此后是filed列表输出,每个filed输出包含int32(tag,type)和value的字节数组,从上文我们知道每个filed都有一个唯一的数字tag表示它的index位置,type为字段的类型,tag和type分别占用一个int的高位、低位字节;如果filed为string、bytes类型,还会在value之前额外的补充添加一个varint32类型的数字,表示string、bytes的字节长度。

    那么在反序列化的时候,首先读取一个32为的int表示serializedSize,然后读取serializedSize个字节保存在一个bytebuffer中,即读取一个完整的package。然后读取一个int32数字,从这个数字中解析出tag和type,如果type为string、bytes,然后补充读取一个varint32就知道了string的字节长度了,此后根据type或者字节长度,读取后续的字节数组并转换成java type。重复上述操作,直到整个package解析完毕。

 

    protobuf的这种序列化format,极大的介绍了输入、输出的数据大小,而且复杂度非常低,从而性能较高。

 

6、protobuf与Netty编程:

    1)Netty Server端样例

 

public class ProtobufNettyServerTestMain {

    public static void main(String[] args) {
        //bossGroup : NIO selector threadPool
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //workerGroup : socket data read-write worker threadPool
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder())
                                    .addLast(new ProtobufDecoder(PersonProtos.Person.getDefaultInstance()))
                                    .addLast(new ProtobufVarint32LengthFieldPrepender())
                                    .addLast(new ProtobufEncoder())
                                    .addLast(new ProtobufServerHandler());//自定义handler
                        }
                    }).childOption(ChannelOption.TCP_NODELAY,true);
            System.out.println("begin");
            //bind到本地的18080端口
            ChannelFuture future = bootstrap.bind(18080).sync();
            //阻塞,直到channel.close
            future.channel().closeFuture().sync();
            System.out.println("end");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //辅助线程优雅退出
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

 

 

    备注:channel内部维护一个pipeline,类似一个filter链表一样,所有的socket读写都会经过,对于write操作(outbound)会从pipeline列表的last-->first方向依次调用Encoder处理器;对于read操作(inbound)会从first-->last依次调用Decoder处理器。此外Encoder处理对于read操作不起效,Decoder处理器对write操作不起效,原理 稍后在Netty相关章节介绍。

 

    ProtobufEncoder:非常简单,内部直接使用了message.toByteArray()将字节数据放入bytebuf中输出(out中,交由下一个encoder处理)。

    ProtobufVarint32LengthFieldPrepender:因为ProtobufEncoder只是将message的各个filed按照规则输出了,并没有serializedSize,所以socket无法判定package(封包)。这个Encoder的作用就是在ProtobufEncoder生成的字节数组前,prepender一个varint32数字,表示serializedSize。

    ProtobufVarint32FrameDecoder:这个decoder和Prepender做的工作正好对应,作用就是“成帧”,根据seriaziedSize读取足额的字节数组--一个完整的package。

    ProtobufDecoder:和ProtobufEncoder对应,这个Decoder需要指定一个默认的instance,decoder将会解析byteArray,并根据format规则为此instance中的各个filed赋值。

    

 

    2)ProtobufServerHandler.java

    发送Protobuf数据和接收client发送的数据。一个自定义的处理器,通常我们的业务会在这里处理。

 

public class ProtobufServerHandler extends ChannelInboundHandlerAdapter {


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        PersonProtos.Person person = (PersonProtos.Person)msg;
       //经过pipeline的各个decoder,到此Person类型已经可以断定
        System.out.println(person.getEmail());
        ChannelFuture future = ctx.writeAndFlush(build());
        //发送数据之后,我们手动关闭channel,这个关闭是异步的,当数据发送完毕后执行。
        future.addListener(ChannelFutureListener.CLOSE);
    }

    /**
     * 构建一个Protobuf实例,测试
     * @return
     */
    public MessageLite build() {
        PersonProtos.Person.Builder personBuilder = PersonProtos.Person.newBuilder();
        personBuilder.setEmail("zhangsan@gmail.com");
        personBuilder.setId(1000);
        PersonProtos.Person.PhoneNumber.Builder phone = PersonProtos.Person.PhoneNumber.newBuilder();
        phone.setNumber("18610000000");

        personBuilder.setName("张三");
        personBuilder.addPhones(phone);

        return personBuilder.build();
    }

}

 

    3)Netty Client样例

 

public class ProtobufNettyClientTestMain {

    public static void main(String[] args) throws Exception{
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workerGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,10000)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("initChannel");
                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder())
                                    .addLast(new ProtobufDecoder(PersonProtos.Person.getDefaultInstance()))
                                    .addLast(new ProtobufVarint32LengthFieldPrepender())
                                    .addLast(new ProtobufEncoder())
                                    .addLast(new ProtobufClientHandler());
                        }
                    });
            ChannelFuture future = bootstrap.connect(new InetSocketAddress("127.0.0.1", 18080));
            System.out.println("begin");
            future.channel().closeFuture().sync();
            System.out.println("Closed");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
        }

    }
}

 

    4)ProtobufClientHandler.java

 

public class ProtobufClientHandler extends ChannelInboundHandlerAdapter {


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //当channel就绪后,我们首先通过client发送一个数据。
        ctx.writeAndFlush(build());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        PersonProtos.Person person = (PersonProtos.Person)msg;
        System.out.println(person.getEmail());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();;
        ctx.close();
    }

    public MessageLite build() {
        PersonProtos.Person.Builder personBuilder = PersonProtos.Person.newBuilder();
        personBuilder.setEmail("lisi@gmail.com");
        personBuilder.setId(1000);
        PersonProtos.Person.PhoneNumber.Builder phone = PersonProtos.Person.PhoneNumber.newBuilder();
        phone.setNumber("18610000000");

        personBuilder.setName("李四");
        personBuilder.addPhones(phone);

        return personBuilder.build();
    }

}

 

    关于Netty的相关技术,请参考其他文档。

 

    到此为止,我们基本上对protobuf使用方式,有了初步的了解。祝大家好运!

 

 

 

Protobuf快速入门 Prorobuf快速入门 阅读详情

相关推荐

Apollo里常用的google protobuf简明教程

protobuf(Google Protocol Buffers)是Google提供一个具有高效的协议数据交换格式工具库(类似Json)。 在看百度Apollo自动驾驶开源代码时,经常会看到.proto文件,刚开始不了解是怎么用的,同时在看代码时经常会看到一些找不到定义的类,这个时候往往导致代码看不下去,在简单了解google protobuf 的使用后,问题都迎刃而解。 .proto里的message类数据结构是Apollo里各模块常用的一种数据结构。 后面将Apollo代码里的规划控制相关模块的算

weixin_39199083的博客 5365

com.google.protobuf学习笔记

Protobuf是什么 Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。protobuf平台无关,语言无关,可扩展,提供了友好的动态库,使用简单,解析速度快,比对应的XML快约20-100倍,序列化数据非常简洁、紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10。 P

蚊子蚊子嗡嗡嗡 1万+

【保姆级】Protobuf详解及入门指南

Protobuf(Protocol Buffers)协议😉 Protobuf 是一种由 Google 开发的二进制序列化格式和相关的技术,它用于高效地序列化和反序列化结构化数据,通常用于网络通信、数据存储等场景。

aqin1012的博客 3万+

Google ProtoBuf用法

一、简介 Google Protobuf是Netty中常用的编解码工具,Protobuf支持数据结构化一次可以到处使用,且可以跨语言使用,通过代码生成工具可以生成不同语言版本的源代码,还可以在使用不同版本的数据结构进程间进行数据传递,实现数据结构向前兼容。这个序列化框架相对于Java本身的序列化API具有性能高,适合不同语言开发的程序之间传输数据。 二、环境搭建 1、软件包下载 使用Pro...

Terisadeng的博客 5449

ARM架构下的SLAM部署避坑指南:香橙派AIpro与D435i深度相机的实战解析

本文详细解析了在ARM架构的香橙派AIpro开发板上部署SLAM算法并与Intel D435i深度相机配合的实战经验。内容涵盖系统配置、ROS编译、驱动安装、算法优化等关键步骤,提供了具体的避坑指南和性能调优技巧,帮助开发者在嵌入式平台上高效实现实时SLAM应用。

f0g1h2的博客 983

量化投资之工具篇一:Backtrader从入门到精通(1)-手把手教你零基础实现一个策略案例

Backtrader是重要的量化框架,本文记录学习该框架的笔记,内容主要基于Backtrader的网站指导文档。虽然该框架目前用于量化投资领域,但是可以作为数据处理的基本架构,进行改造后用于各种数据的处理,尤其适用于对原始数据处理完成后应用一定的策略进行预测以及可视化处理。 1、简介 Backtrader的特点,就是两点: 1、易于使用; 2、参见第1条。 那么如何使用Backtrader呢?比把大象装进冰箱复杂点,一共4步: 创建一个Cerebro引擎: 加入一个Strategy...

仓鼠王的博客 5万+

protobuf java object_protobuf 与 Java 对象互转

Java使用protobuf时,往往需要在Java对象(比如POJO)和protobuf message的Java对象间互转:protobuf接口需要传入message参数: 把POJO转成message, 作为接口参数;protobuf接口会返回message参数: 需要把message转成POJO, 供后续使用.比如:protobuf的messagemessage HelloRequest {...

weixin_33796288的博客 2411

GaN功率放大器设计避坑指南:从仿真到实测的Doherty PA完整流程(基于ADS 2023)

本文详细介绍了基于ADS 2023软件,从理论计算、电路仿真到版图后仿真的GaN Doherty功率放大器完整设计流程。文章聚焦C波段应用,深入剖析了负载调制网络设计、稳定性处理、版图电磁仿真等关键环节中的常见误区与工程折衷,为工程师提供了一套从设计到实测的实战避坑指南。

weixin_29238147的博客 530

protobuf-java-lite 和 protobuf-java 的区别

这是Protocol Buffers的精简版,也称为,主要用于嵌入式系统和移动设备等资源受限的环境。它去除了protobuf-java中的一些不常用的特性和功能,以减小库的体积并提高性能。:这是Protocol Buffers的Java版本,提供了丰富的API和工具,方便Java开发者使用Protocol Buffers进行数据序列化和反序列化。它支持Java语言的所有特性,并提供了一些额外的功能,如动态消息、反射等。

阿饱同学 1134

手把手教你用野火FPGA开发板资料包安装ModelSim 10.5se(附破解教程)

本文提供了一份详细的指南,手把手教你为野火FPGA开发板安装和配置ModelSim 10.5se仿真工具。内容涵盖从前期准备、软件安装、许可证激活(学习用途)到环境验证的全过程,并简要介绍了如何与Xilinx Vivado开发套件集成,帮助初学者快速搭建稳定的FPGA仿真环境。

lstm7chronicler的博客 250

【系列05】端侧AI:构建与部署高效的本地化AI模型 第4章:模型量化(Quantization)

量化的基本思想是减少模型中用于表示参数和激活值的比特数。在模型训练时,参数通常使用32位浮点数(FP32)进行存储,这提供了高精度,但也消耗大量的内存和计算资源。量化则将这些32位浮点数转换成低比特数表示,通常是8位整数(INT8)。量化的原理可以概括为:对浮点数范围进行校准,并将其映射到更小的整数范围内。例如,将一个FP32的权重(如-1.5到1.5)映射到INT8的范围(-128到127)。在推理过程中,模型将使用这些低精度的整数进行计算,从而大大减少了所需的计算量。量化带来的主要收益减少模型大小。

学习,输出==》再学习再输出 1214

java - Protobuf

在项目中创建.proto 文件在进行 proto(Protocol Buffers)和 JSON 库的性能对比时,我们观察到,两者在单次解析过程中的平均时间均低于1毫秒。无论是采用 Protocol Buffers 还是 JSON 作为数据序列化和反序列化的机制,它们都具备高效处理能力,非常适合用于数据密集型的通信框架。这种高效的数据处理能力确保了在网络通信中,即使是在数据量较大或请求频率较高的情况下,这两种技术也能提供稳定且迅速的数据流转换,从而满足现代应用程序对于性能的严格要求。

aRtHuR1207的博客 1546

【零基础入门unity游戏开发——unity通用篇30】Resources资源加载(基于unity6开发介绍)

Resources资源加载(基于unity6开发介绍)

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 4116

java中使用protobuf总结

java中读写protobuf

hsy12342611的专栏 3631

华为OD机试双机位C卷:打印机队列 (C++/Py/C/Java/Js/Go)

华为OD机试双机位C卷 打印机队列,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解。华为OD机试 - 打印机队列。

qq_45776114的博客 1793

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Java中使用protobuf

Java中使用protobuf

AiFlutter的博客 1462

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

java protobuf mac 安装_Mac安装Protobuf编译Java

本文整理了再在Mac上安装Protobuf 和编译Java的详细过程在Mac上安装protobuf创建一个java项目,编写.proto文件用protobuf编译生成java文件,测试用wire编译生成java文件,测试1.protobuf下载地址:https://github.com/google/protobuf/tags?after=v3.0.0-alpha-1Github:https://...

weixin_31310737的博客 437

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

protobuf java 反射

需求: 线上需要一份数据,这份数据是存储在hbase中的(比如对于某一个实体,其各个字段是存储在hbase的各个列的)。而希望最终导出的文件的每一行是一个 protobuf 的message,以方便解析和维护。 具体做法: 定义一个 protobuf  message,其各个 field 的名字与 hbase 各列的 key 的名字对应,将 hbase 中各列对应的 value 取出来,填充

5567

Mac安装Protobuf编译Java

本文整理了再在Mac上安装Protobuf 和编译Java的详细过程 在Mac上安装protobuf创建一个java项目,编写.proto文件用protobuf编译生成java文件,测试用wire编译生成java文件,测试 1.protobuf下载地址:https://github.com/google/protobuf/tags?after=v3.0.0-alpha-1 Git

顾明伟 1万+

mac protobuf java_Mac安装Protobuf编译Java

本文整理了再在Mac上安装Protobuf 和编译Java的详细过程在Mac上安装protobuf创建一个java项目,编写.proto文件用protobuf编译生成java文件,测试用wire编译生成java文件,测试1.protobuf下载地址:https://github.com/google/protobuf/tags?after=v3.0.0-alpha-1Github:https://...

weixin_35130561的博客 258

Protobuf 在 Java 中的入门实例

Protobuf1 是一种语言中立、平台无关、可扩展的序列化数据的格式,可用于通信协议,数据存储等。 本文将演示在 Java 语言中如何编写一个 Protobuf 的入级程序,也许你可能并不了解 Protobuf,这没有关系,基于 Protobuf 官方文档的衍生博文已经安排上了,只是限于内容较多,我正在一点点写作中,让我们先来简单实战吧! 注: 本文及后续所有关于 Protobuf 相关文章均采...

Jitwxs 1712

protobuf(java)

文章目录1.介绍1.1 Java序列化2.使用2.1 IDEA配置2.2 添加依赖pom2.3 编写protobuf配置文件person.proto2.4 在src\main\创建proto目录,并把配置文件存放于此2.5 编译2.6 运行参考 1.介绍 序列化需要考虑? 1.序列化之后的码流大小(占用网络带宽) 2.序列化和反序列化的性能(CPU资源占用) 3.是否支持跨语言 protobuf:...

有点想法的专栏 1041

protobuf java_protobuf基于java入门

protobuf基于java入门1. 编写protobuf文件——person.protopackage protobuf;option java_package="com.sean.person";option java_outer_classname = "PersonEntity";message Person{required int32 id = 1;required string na...

weixin_42508290的博客 156

Protobuf 之java使用篇

碰巧用到Proto,算是笔记吧算是笔记吧, windows : 1,两个文件:proto.exe,  protobuf-Java-2.4.1.jar 2,建立一个工程TestPb,在下面建立一个proto文件件,用来存放【。proto】文件 3,将proto,exe放在工程下, 4,建立一个msg.proto文件: option java_package = "com.protob

业精于勤荒于嬉;行成于思,毁于随。 4295
上一篇: Jenkins + Git + Maven + tomcat集成环境搭建
下一篇: Nginx学习总结:geo与image模块(四)
shift_alt_ctrl
博客等级 码龄10年 0粉丝 83原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值