与传统序列化比,PB更快更节省空间

news2024/12/28 6:04:28

文章目录

  • 为何选择PB
  • PB安装
    • Windows
    • Mac未完待续
  • 语法
    • 命令行编译
    • Maven插件编译
    • UDP通信的例子
  • 3大序列化方法对比

为何选择PB

在这里插入图片描述
在网络传输和存储数据的时候比传统的 JSON 效果更好

PB安装

GitHub

Windows

  1. 下载
    在这里插入图片描述
  2. 配置环境变量
    在这里插入图片描述
  3. 验证
    在这里插入图片描述

Mac未完待续

后续补充Mac安装方式

语法

在这里插入图片描述
使用过程很简单,并没有太多的语法关注点。我们只需要掌握重要的一些方法即可

创建的 .proto 文件一定要全部小写,中间用 “_” 链接【lower_snake_case.proto】

// 字段规则,说明是 proto3 语法
syntax = "proto3";
// 包名
package contact;

// 开启多文件
option java_multiple_files = true;
// 生成的 .java 文件的包路径
option java_package = "entityPB";
// 生成的 .proto 包装类的 .java 文件的类名
option java_outer_classname = "ContactsProto";

// 需要用到 any 数据类型就需要导入包【protoc-23.1-win64\include\google\protobuf】
import "google/protobuf/any.proto";

// message 消息类型命名规范:使用驼峰命名,首字母大写
message PeopleInfoPB{
  /*
  字段定义格式为:字段类型 字段名 = 字段唯⼀编号
    字段名称命名规范:全小写字⺟,多个字⺟之间⽤ _ 连接。
    字段类型分为:标量数据类型 和 特殊类型(包括枚举、其他消息类型等)。
    字段唯⼀编号:⽤来标识字段,⼀旦开始使⽤就不能够再改变。
   */
  string              name   = 1;// 姓名
  int32               age    = 2;// 年龄
  message Phone{
    string    number = 1;// 电话号码
    /*
    枚举
    同一文件下枚举类型不能出现相同的字段
     */
    enum PhoneType {
      MP  = 0;// 移动电话
      TEL = 1;// 固定电话
    }
    PhoneType type   = 2;// 电话类型
  }
  // repeated 说明 phone 这个数据是一个可重复的,也就是数组的形式
  repeated Phone      phone  = 3;
  /*
  oneof:如果消息中有很多字段,但是只会用到一个字段。后续设置的 wechat 会将 QQ 清空
   */
  oneof other_contact{// 其它联系方式
    string qq     = 4;
    string wechat = 5;
  }
  /*
  any 类型可以理解为泛型类型
  可以用 repeated 修饰
   */
  google.protobuf.Any data   = 6;// 存放联系地址
  /*
  map 不能用 repeated 修饰
  key:除了 float,bytes 以外任意的类型
  value:任意类型
   */
  map<string, string> remark = 7;// 备注
}

message Address{
  string home_address = 1;// 家庭地址
  string unit_address = 2;// 公司地址
}

message Contacts {
  repeated PeopleInfoPB contacts = 1;// 通讯录
}

.protoType标量类型Notesjava
int32使⽤变⻓编码[1]。负数的编码效率较低,若字段可能为负值,应使⽤ sint32 代替int
int64使⽤变⻓编码[1]。负数的编码效率较低,若字段可能为负值,应使⽤ sint64 代替int
uint32使⽤变⻓编码[1]int
uint64使⽤变⻓编码[1]int
sint32使⽤变⻓编码[1]。符号整型。负值的编码效率⾼于常规的 int32 类型int
sint64使⽤变⻓编码[1]。符号整型。负值的编码效率⾼于常规的 int64 类型long
fixed32定⻓ 4 字节。若值常⼤于2^28 则会⽐ uint32 更⾼效int
fixed64定⻓ 8 字节。若值常⼤于2^56 则会⽐ uint64 更⾼效long
sfixed32定⻓ 4 字节int
sfixed64定⻓ 8 字节long
floatfloat
doubledouble
bytes可包含任意的字节序列但⻓度不能超过 2^32ByteString
boolboolean
string包含 UTF-8 和 ASCII 编码的字符串,⻓度不能超过2^32string
类型
string空字符串
bytes空字节
boolfalse
int0
enum枚举默认值是第一个枚举值,必须为0
消息字段未设置该字段,默认值依赖于具体的语言
repeated修饰默认是一个列表【addXXX方法】
对于消息字段,oneof字段和any字段都有has方法来检测当前字段是否被设置值

命令行编译

# protoc -I 搜索路径 --java_out=输出的java文件路径 .proto文件
protoc -I BasicGrammar/src/main/proto/start --java_out=BasicGrammar/src/main/java contacts.proto

这种每次不方便,因此衍生出插件编译

Maven插件编译

要选择版本对应的。我的 protocol buff 是 3.23.1,那么插件版本对应的也应该是 3.23.1

maven-repository仓库在这里插入图片描述

<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java 版本对应【23.1】-->
<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.23.1</version>
</dependency>

<plugin>
    <!-- https://mvnrepository.com/artifact/org.xolstice.maven.plugins/protobuf-maven-plugin -->
    <groupId>org.xolstice.maven.plugins</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.6.1</version>
    <configuration>
        <!--本地安装的protoc.exe运行路径-->
        <protocExecutable>D:\Documents\Tools\protoc-23.1-win64\bin\protoc.exe</protocExecutable>
        <!--protoc文件放置的目录,默认为/src/main/proto-->
        <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
        <!--生成文件的目录,默认生成到target/generated-sources/protobuf/下-->
        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
        <!--是否清空目标目录,默认值为true。这个最好设置为false,以免误删项目文件-->
        <clearOutputDirectory>false</clearOutputDirectory>
    </configuration>
</plugin>

每次双击插件即可完成编译指令
在这里插入图片描述

UDP通信的例子

网络数据传输中需要对数据进行序列化和反序列化
.客户端protp文件代码

syntax = "proto3";
package client_internet;

option java_multiple_files = true;
option java_package = "internet.client";
option java_outer_classname = "ContactsProtos";

message Request{
  string         name  = 1;
  int32          age   = 2;
  message Phone{
    string number = 1;
  }
  repeated Phone phone = 3;
}

message Response{
  string uid = 1;
}

客户端Java代码

package internet.client;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class ContactsClient {
    private static void clientStart(String ip, int port) throws IOException {
        // 1.创建客户端 socket
        DatagramSocket socket = new DatagramSocket();
        // 2.序列化发送给服务端的数据
        Request req = Request.newBuilder().setName("zhang san").setAge(20).addPhone(Request.Phone.newBuilder().setNumber("177-9824-4450")).build();
        byte[] reqData = req.toByteArray();
        // 3.给服务端发送数据
        DatagramPacket reqPacket = new DatagramPacket(reqData, reqData.length, InetAddress.getByName(ip), port);
        socket.send(reqPacket);
        // 4.接收服务端数据
        DatagramPacket respPacket = new DatagramPacket(new byte[8192], 8192);
        socket.receive(respPacket);
        // 5.反序列化接收到的服务端数据
        int len = respPacket.getLength();
        byte[] respData = respPacket.getData();
        byte[] respNewData = new byte[len];
        System.arraycopy(respData, 0, respNewData, 0, len);
        Response response = Response.parseFrom(respNewData);
        System.out.printf("接收服务端数据:" + response.toString());
        socket.close();
    }

    public static void main(String[] args) throws IOException {
        String ip = "127.0.0.1";
        int port = 9090;
        clientStart(ip, port);
    }
}

在这里插入图片描述

服务端 .proto 代码

syntax = "proto3";
package service_internet;

option java_multiple_files = true;
option java_package = "internet.service";
option java_outer_classname = "ContactsProtos";

message Request{
  string         name  = 1;
  int32          age   = 2;
  message Phone{
    string number = 1;
  }
  repeated Phone phone = 3;
}

message Response{
  string uid = 1;
}

服务端代码

package internet.service;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.charset.StandardCharsets;

// 服务端反序列化
public class ContactsService {
    private static void startService(int port) throws IOException {
        // 1.创建服务端 socket
        DatagramSocket socket = new DatagramSocket(port);
        while (true) {
            System.out.println("等待客户端发送数据...");
            // 2.接收客户端数据
            DatagramPacket reqPacket = new DatagramPacket(new byte[8192], 8192);
            socket.receive(reqPacket);
            // 3.反序列化接收到的客户端数据
            byte[] reqData = reqPacket.getData();
            int len = reqPacket.getLength();
            byte[] reqNewData = new byte[len];
            System.arraycopy(reqData, 0, reqNewData, 0, len);
            Request request = Request.parseFrom(reqNewData);
//            System.out.println("接收客户端端数据:" + new String(request.toByteArray(), StandardCharsets.UTF_8));
            System.out.println("接收客户端端数据:" + request.toString());
            // 4.序列化发送给客户端的数据
            Response response = Response.newBuilder().setUid("200").build();
            byte[] respData = response.toByteArray();
            // 5.给客户端发送数据
            DatagramPacket respPacket = new DatagramPacket(respData, 0, respData.length, reqPacket.getSocketAddress());
            socket.send(respPacket);
        }
    }

    public static void main(String[] args) throws IOException {
        int port = 9090;
        startService(port);
    }
}

在这里插入图片描述

3大序列化方法对比

PB.proto 代码

// 字段规则,说明是 proto3 语法
syntax = "proto3";
// 包名
package contact;

// 开启多文件
option java_multiple_files = true;
// 生成的 .java 文件的包路径
option java_package = "entityPB";
// 生成的 .proto 包装类的 .java 文件的类名
option java_outer_classname = "ContactsProto";

// 需要用到 any 数据类型就需要导入包【protoc-23.1-win64\include\google\protobuf】
import "google/protobuf/any.proto";

// message 消息类型命名规范:使用驼峰命名,首字母大写
message PeopleInfoPB{
  /*
  字段定义格式为:字段类型 字段名 = 字段唯⼀编号
    字段名称命名规范:全小写字⺟,多个字⺟之间⽤ _ 连接。
    字段类型分为:标量数据类型 和 特殊类型(包括枚举、其他消息类型等)。
    字段唯⼀编号:⽤来标识字段,⼀旦开始使⽤就不能够再改变。
   */
  string              name   = 1;// 姓名
  int32               age    = 2;// 年龄
  message Phone{
    string    number = 1;// 电话号码
    /*
    枚举
    同一文件下枚举类型不能出现相同的字段
     */
    enum PhoneType {
      MP  = 0;// 移动电话
      TEL = 1;// 固定电话
    }
    PhoneType type   = 2;// 电话类型
  }
  // repeated 说明 phone 这个数据是一个可重复的,也就是数组的形式
  repeated Phone      phone  = 3;
  /*
  oneof:如果消息中有很多字段,但是只会用到一个字段。后续设置的 wechat 会将 QQ 清空
   */
  oneof other_contact{// 其它联系方式
    string qq     = 4;
    string wechat = 5;
  }
  /*
  any 类型可以理解为泛型类型
  可以用 repeated 修饰
   */
  google.protobuf.Any data   = 6;// 存放联系地址
  /*
  map 不能用 repeated 修饰
  key:除了 float,bytes 以外任意的类型
  value:任意类型
   */
  map<string, string> remark = 7;// 备注
}

message Address{
  string home_address = 1;// 家庭地址
  string unit_address = 2;// 公司地址
}

message Contacts {
  repeated PeopleInfoPB contacts = 1;// 通讯录
}

普通的Java实体类

package entity;

import java.util.HashMap;
import java.util.List;

public class PeopleInfoEntity {
    private String name;
    private int age;
    private String qq;

    public static class Phone {
        private String number;
        public static enum PhoneType {
            MP, TEL;
        }
        PhoneType type;

        public String getNumber() {
            return number;
        }

        public void setNumber(String number) {
            this.number = number;
        }

        public PhoneType getType() {
            return type;
        }

        public void setType(PhoneType type) {
            this.type = type;
        }

        @Override
        public String toString() {
            return "Phone{" +
                    "number='" + number + '\'' +
                    ", type=" + type +
                    '}';
        }
    }
    private List<Phone> phones;

    public static class Address {
        private String home_address;
        private String unit_address;

        public String getHome_address() {
            return home_address;
        }

        public void setHome_address(String home_address) {
            this.home_address = home_address;
        }

        public String getUnit_address() {
            return unit_address;
        }

        public void setUnit_address(String unit_address) {
            this.unit_address = unit_address;
        }

        @Override
        public String toString() {
            return "Address{" +
                    "home_address='" + home_address + '\'' +
                    ", unit_address='" + unit_address + '\'' +
                    '}';
        }
    }
    private Address address;
    private HashMap<String, String> remark;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getQq() {
        return qq;
    }

    public void setQq(String qq) {
        this.qq = qq;
    }

    public List<Phone> getPhones() {
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public HashMap<String, String> getRemark() {
        return remark;
    }

    public void setRemark(HashMap<String, String> remark) {
        this.remark = remark;
    }

    @Override
    public String toString() {
        return "PeopleInfoEntity{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", qq='" + qq + '\'' +
                ", phones=" + phones +
                ", address=" + address +
                ", remark=" + remark +
                '}';
    }
}

效率对比测试代码

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.Any;
import com.google.protobuf.InvalidProtocolBufferException;
import entity.PeopleInfoEntity;
import entityPB.Address;
import entityPB.PeopleInfoPB;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class TestJSON {
    private static PeopleInfoEntity createEntity() {
        PeopleInfoEntity peopleInfo = new PeopleInfoEntity();
        peopleInfo.setName("张三");
        peopleInfo.setAge(24);
        // 添加电话
        List<PeopleInfoEntity.Phone> phones = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            PeopleInfoEntity.Phone phone = new PeopleInfoEntity.Phone();
            phone.setNumber("193-0719-3096");
            phone.setType(PeopleInfoEntity.Phone.PhoneType.MP);
            phones.add(phone);
        }
        peopleInfo.setPhones(phones);
        peopleInfo.setQq("1969-612859");
        PeopleInfoEntity.Address address = new PeopleInfoEntity.Address();
        address.setHome_address("湖北省十堰市");
        address.setUnit_address("湖北省武汉市");
        peopleInfo.setAddress(address);
        HashMap<String, String> remark = new HashMap<String, String>() {{
            put("key1", "value1");
            put("key2", "value2");
            put("key3", "value3");
            put("key4", "value4");
            put("key5", "value5");
            put("key6", "value6");
        }};
        peopleInfo.setRemark(remark);
        return peopleInfo;
    }

    private static PeopleInfoPB createEntityPB() {
        PeopleInfoPB.Builder peopelInfoBuilder = PeopleInfoPB.newBuilder();
        peopelInfoBuilder.setName("张三");
        peopelInfoBuilder.setAge(24);
        // 设置 repeated+enum 数据类型
        for (int i = 1; i <= 5; i++) {
            PeopleInfoPB.Phone.Builder phoneBuilder = PeopleInfoPB.Phone.newBuilder();
            phoneBuilder.setNumber("193-0719-3096");
            phoneBuilder.setType(PeopleInfoPB.Phone.PhoneType.MP);
            peopelInfoBuilder.addPhone(phoneBuilder);
        }
        // 设置 oneof 数据类型
        peopelInfoBuilder.setQq("1969-612859");
        // 设置 Any 数据类型
        Address.Builder addressBuilder = Address.newBuilder();
        addressBuilder.setHomeAddress("湖北省十堰市");
        addressBuilder.setUnitAddress("湖北省武汉市");
        peopelInfoBuilder.setData(Any.pack(addressBuilder.build()));
        // 设置 map 备注
        peopelInfoBuilder.putRemark("key1", "value1");
        peopelInfoBuilder.putRemark("key2", "value2");
        peopelInfoBuilder.putRemark("key3", "value3");
        peopelInfoBuilder.putRemark("key4", "value4");
        peopelInfoBuilder.putRemark("key5", "value5");
        peopelInfoBuilder.putRemark("key6", "value6");
        return peopelInfoBuilder.build();
    }

    private static void testFastJSON2(PeopleInfoEntity peopleInfo, int count) {
        long beg = System.currentTimeMillis();
        String jsonStr = "";
        PeopleInfoEntity peopleInfo1 = null;
        for (int i = 0; i < count; i++) {
            jsonStr = JSON.toJSONString(peopleInfo);
        }
        long end = System.currentTimeMillis();
        System.out.printf("%d次 fastjson2 序列化耗时:%d ms;序列化后大小:%d\n", count, end - beg, jsonStr.length());
        beg = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            peopleInfo1 = JSON.parseObject(jsonStr, PeopleInfoEntity.class);
        }
        end = System.currentTimeMillis();
        System.out.printf("%d次 fastjson2 反序列化耗时:%d ms\n", count, end - beg);
    }

    private static void testJackson(PeopleInfoEntity peopleInfo, int count) throws JsonProcessingException {
        long beg = System.currentTimeMillis();
        String jsonStr = "";
        PeopleInfoEntity peopleInfo1 = null;
        ObjectMapper mapper = new ObjectMapper();
        for (int i = 0; i < count; i++) {
            jsonStr = mapper.writeValueAsString(peopleInfo);
        }
        long end = System.currentTimeMillis();
        System.out.printf("%d次 jackson   序列化耗时:%d ms;序列化后大小:%d\n", count, end - beg, jsonStr.length());
        beg = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            peopleInfo1 = mapper.readValue(jsonStr, PeopleInfoEntity.class);
        }
        end = System.currentTimeMillis();
        System.out.printf("%d次 jackson   反序列化耗时:%d ms\n", count, end - beg);
    }

    private static void testPB(PeopleInfoPB peopleInfo, int count) throws InvalidProtocolBufferException {
        long beg = System.currentTimeMillis();
        byte[] jsonBytes = null;
        PeopleInfoPB peopleInfo1 = null;
        for (int i = 0; i < count; i++) {
            jsonBytes = peopleInfo.toByteArray();
        }
        long end = System.currentTimeMillis();
        System.out.printf("%d次 PB        序列化耗时:%d ms;序列化后大小:%d\n", count, end - beg, jsonBytes.length);
        beg = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            peopleInfo1 = PeopleInfoPB.parseFrom(jsonBytes);
        }
        end = System.currentTimeMillis();
        System.out.printf("%d次 PB        反序列化耗时:%d ms\n", count, end - beg);
    }

    public static void main(String[] args) throws JsonProcessingException, InvalidProtocolBufferException {
        int count = 10000;
        // entity对象
        PeopleInfoEntity peopleInfoEntity = createEntity();
        testFastJSON2(peopleInfoEntity, count);
        testJackson(peopleInfoEntity, count);
        // pb对象
        PeopleInfoPB peopleInfoPB = createEntityPB();
        testPB(peopleInfoPB, count);
    }
}

在这里插入图片描述

发现PB的效率很快,而且序列化后文件大小也很小

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/594897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Word、Excel、PPT题库——“办公自动化”

小雅兰期末加油冲冲冲&#xff01;&#xff01;&#xff01; 1.【单选题】下列文件扩展名,不属于Word模板文件的是&#xff08; A &#xff09;。 A. .DOCX B. .DOTM C. .DOTX D. .DOT 本题的考查点是word基本知识的了解。 .DOCX&#xff1a;word文档。 .DOTM&#xff1a;启…

目标检测:RPN — Faster R-CNN 的主干

动动发财的小手&#xff0c;点个赞吧&#xff01; 在使用 R-CNN 的目标检测中&#xff0c;RPN 是真正的主干&#xff0c;并且到目前为止已被证明非常有效。它的目的是提出在特定图像中可识别的多个对象。 这种方法是由 Shaoqing Ren、Kaiming He、Ross Girshick 和 Jian Sun 在…

Pandas 28种常用方法使用总结

Pandas库专为数据分析而设计&#xff0c;它是使Python成为强大而高效的数据分析环境的重要因素。它提供了多种数据结构和方法来处理和分析数据。下面是一些Pandas常用方法的使用总结。 1. 创建数据框 使用read_csv()或read_excel()方法读取数据文件&#xff0c;也可以使用Dat…

饶派杯XCTF车联网安全挑战赛Reverse GotYourKey

文章目录 一.程序逻辑分析二.线程2的operate方法解析三.找出真flag 一.程序逻辑分析 onCreate方法中判断SDK版本是否>27 然后创建两个线程 第一个线程是接受输入的字符串并发送出去 第二个线程用于接受数据 线程1,就是将字符串转为字节数组发送出去 线程2,作为服务端接受…

knife4j、swagger、springdoc 返回接口分组排序问题

一、直击问题 解决前后顺序对比 解决方法&#xff1a; 在配置文件中添加排序规则方法sortTagsAlphabetically&#xff1a; package com.example.demo.config;import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.enums.Security…

OpenMMlab的整体概述和作用

是什么&#xff1f; 开源算法体系&#xff08;非框架、有开源代码&#xff09; 用pytorch实现 优势 开箱即用&#xff0c;复现了很多顶会论文中的算法。每个cv任务对应算法库&#xff0c;其中顺序即为学习路线。便于对比实验。 使用统一的框架、超参数&#xff0c;做对比实…

测试接口遇到APP加密?先来了解一下算法思路~

背景 服务端与客户端进行http通讯时&#xff0c;为了防止被爬虫&#xff0c;数据安全性等&#xff0c;引入APP通信加密&#xff0c;简单来说&#xff0c;就是引入签名sign&#xff0c;APP的所有请求都会经过加密签名校验流程。常见的加密方案有AES加密&#xff0c;RSA加密&…

性能测试1

目录 1.什么是性能测试 1.1性能测试的定义 1.2性能测试和功能测试的区别 1.3影响一个软件性能因素有什么影响 2.为什么是性能测试 3.性能测试常见的术语和性能测试衡量指标 3.1并发用户数 3.2响应时间/平均响应时间&#xff08;RT/ART) 3.3事务响应时间 3.4每秒事务通…

yolov5训练时遇到的问题

torch会自动被requirement.txt替换 在对yolov5_5.0进行pip install requirement.txt后&#xff0c;yolo5_5.0会将虚拟环境中中的torch替换为2.0.1版本的&#xff0c;但要注意查看该torch是否为gpu版本&#xff0c;查看方式如下&#xff1a;打开Anaconda Prompt&#xff0c;激活…

分布式爬虫框架

分布式爬虫框架分为两种&#xff1a;控制模式&#xff08;左&#xff09;和自由模式&#xff08;右&#xff09;&#xff1a; 控制模式中的控制节点是系统实现中的瓶颈&#xff0c;自由模式则面临爬行节点之间的通信处理问题。因此&#xff0c;在实际工程中&#xff0c;我们通常…

go语言命令行工具cobra

go语言命令行工具cobra 1、Cobra 介绍 Cobra 是关于 golang 的一个命令行解析库&#xff0c;用它能够快速创建功能强大的 cli 应用程序和命令行工具。 cobra既是一个用于创建强大现代CLI应用程序的库&#xff0c;也是一个生成应用程序和命令文件的程序。cobra被用在很多 go…

【从球开始渲染小姐姐】DAY1----用blender捏一个小姐姐

Building Blender/Windows - Blender Developer Wikihttps://wiki.blender.org/wiki/Building_Blender/Windows How to build Blender on Windows? - YouTubehttps://www.youtube.com/watch?vb6CtGm4vbng bf-blender - Revision 63388: /trunk/lib/win64_vc15https://svn.b…

DJ4-6 虚拟存储器的基本概念

目录 4.6.1 虚拟存储器的引入 1、常规存储器管理方式的特征 2、内存的扩充方法 4.6.2 局部性原理 4.6.3 虚拟存储器的定义 1、虚拟存储器的基本工作情况 2、虚拟存储器的定义 3、虚拟存储器的实现方法 4.6.4 虚拟存储器的特征 基本分页和基本分段不能解决的问题&a…

snpEFF和bedtools基因注释有何异同?

大家好&#xff0c;我是邓飞&#xff0c;现在写博客越来越繁琐了&#xff0c;每个平台对图片都有自己的规则&#xff0c;不能通用&#xff0c;各种找不到图片&#xff0c;本着充值是我变强的原则&#xff0c;买了Markdown Nice的VIP&#xff08;https://product.mdnice.com/&am…

自然语言处理从入门到应用——自然语言处理(Natural Language Processing,NLP)基础知识

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 自然语言通常指的是人类语言&#xff0c;是人类思维的载体和交流的基本工具&#xff0c;也是人类区别于动物的根本标志&#xff0c;更是人类智能发展的外在体现形式之一。自然语言处理&#xff08;Natural Language Pr…

C Primer Plus第十四章编程练习答案

学完C语言之后&#xff0c;我就去阅读《C Primer Plus》这本经典的C语言书籍&#xff0c;对每一章的编程练习题都做了相关的解答&#xff0c;仅仅代表着我个人的解答思路&#xff0c;如有错误&#xff0c;请各位大佬帮忙点出&#xff01; 由于使用的是命令行参数常用于linux系…

LeetCode:1143.最长公共子序列 1035.不相交的线 53. 最大子序和

1143.最长公共子序列 题目 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除…

字节和滴滴划水5年,总结出来的真实经验....

先简单交代一下背景吧&#xff0c;某不知名 985 的本硕&#xff0c;17 年毕业加入字节&#xff0c;之后跳槽到了滴滴&#xff0c;一直从事软件测试的工作。之前没有实习经历&#xff0c;算是5年的工作经验吧。 这5年之间完成了一次晋升&#xff0c;换了一家公司&#xff0c;有…

基础巩固(四)View体系与事件分发

文章目录 Android窗口机制ViewRootWindow、WindowManager、ViewRoot、Activity、DecorView之间的关系ViewView的生命周期Attachment / DetachmentTraversalsState Save / Restoreinvalidate()和requestLayout() View的生命周期与Activity的生命周期的关联Activity创建时如何关联…

[深度学习]yolov7 pytorch模型转onnx,转ncnn模型和mnn模型使用细节

文章目录 前言1.前置1.1 安装必要的库1.2 .pt 权重转ncnn 和mnn所需要的权重 2、编码C项目1.ncnn2.mnn 总结 前言 yolov7 pytorch模型转onnx&#xff0c;转ncnn模型和mnn模型使用细节&#xff0c;记录一下 git仓库&#xff1a; yolov7 https://github.com/WongKinYiu/yolov7 n…