当前位置: 首页 > news >正文

Protobuf原理与序列化

本文目录

  • 1. Protobuf介绍
  • 2. Protobuf的优势
  • 3. 编写Protobuf
    • 头部全局定义
    • 消息结构具体定义
    • 字段类型定义
    • 标签号
    • Base128编码
  • 4. TLV
    • Protobuf的TLV编码
    • 如何通过Varint表示300?
  • 5. 编译Protobuf
  • 6. 构造消息对象

前言:之前写项目的时候只是简单用了下Protobuf,以为就弄懂protobuf了,今天刚好跟朋友聊天,被朋友拷打知不知道Protobuf原理,ok,确实不是很懂, 找了一些文章看看来搞懂,于是就有了这篇文章。

1. Protobuf介绍

在网络通信和数据存储的时候,数据序列化 是非常重要的,特别是现在微服务横行,序列化更是至关重要。传统HTTP通信的时候,一般都是用Json作为消息传递的数据格式。但是谷歌一直在用Protobuf,这肯定是有原因的,所以特意学习了一下Protobuf,来研究研究。

Protobuf(Protocol Buffers)是由 Google 开发的一种轻量级、高效的数据交换格式,它被用于结构化数据的序列化、反序列化和传输。相比于 XML 和 JSON 等文本格式,Protobuf 具有更小的数据体积、更快的解析速度和更强的可扩展性。

核心思想:使用协议(Protocol)来定义数据的结构和编码方式。使用 Protobuf,可以先定义数据的结构各字段的类型字段等信息,然后使用Protobuf提供的编译器生成对应的代码,用于序列化和反序列化数据。由于 Protobuf 是基于二进制编码的,因此可以在数据传输和存储中实现更高效的数据交换,同时也可以跨语言使用。

比如下面这张图,就是很好的一个例子。Java语言写序列化,然后接收端用Python进行反序列化。

在这里插入图片描述

2. Protobuf的优势

更小的数据量:Protobuf 的二进制编码通常比 XML 和 JSON 小 3-10 倍,因此在网络传输和存储数据时可以节省带宽和存储空间。

更快的序列化和反序列化速度:由于 Protobuf 使用二进制格式,所以序列化和反序列化速度比 XML 和 JSON 快得多。

跨语言:Protobuf 支持多种编程语言,可以使用不同的编程语言来编写客户端和服务端。这种跨语言的特性使得 Protobuf 受到很多开发者的欢迎(JSON 也是跨语言的)。

易于维护可扩展:Protobuf 使用 .proto 文件定义数据模型和数据格式,这种文件比 XML 和 JSON 更容易阅读和维护,且可以在不破坏原有协议的基础上,轻松添加或删除字段,实现版本升级和兼容性。

3. 编写Protobuf

// 文件:addressbook.proto
syntax = "proto3";// 指定 Protobuf 包名,防止有相同类名的message定义
package goprotobuf;// Go 生成的包路径 可以通过 go_package 选项指定
option go_package = "/";message Person {// =1,=2 作为序列化后的二进制编码中的字段的唯一标签,也因此,1-15 比 16 会少一个字节,所以尽量使用 1-15 来指定常用字段。optional int32 id = 1;optional string name = 2;optional string email = 3;enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2;}message PhoneNumber {optional string number = 1;optional PhoneType type = 2;}repeated PhoneNumber phones = 4;
}message AddressBook {repeated Person people = 1;
}

头部全局定义

syntax = "proto3":指定 Protobuf 版本为版本3(最新版本)
option go_package = "/": Go 生成的包路径,可以通过 go_package 选项指定

消息结构具体定义

message Person 定一个了一个 Person 类。

其中:
修饰符 optional 表示可选字段,可以不赋值。
修饰符 repeated 表示数据重复多个,如数组,如 List。
修饰符 required 表示必要字段,必须给值,否则会报错 RuntimeException,但是在 Protobuf 版本 3 中被移除。

字段类型定义

修饰符后面跟着的是 字段类型,比如 string字符串、bytes二进制数据类型、enum枚举类型,message消息类型,可以嵌套其他的消息类型。bool布尔类型,只有两个值,true和false。

标签号

字段后面的 =1 这种 是作为 序列化之后的 二进制编码 中的 字段 的对应标签。因为protobuf消息在序列化之后是不包含字段信息的,只有对应的字段序号,所以节省了对应的空间。

尽量使用1-15编号,比16少一个字节,这里我们来讲讲为什么。

Base128编码

Protobuf 使用一种称为 Base 128 编码(也称为 LEB128 或 Protobuf 的 Varint 编码)来表示字段标签号和字段值。这种编码方式会根据数值的大小动态分配字节数,以节省空间。具体规则如下:

字段标签号的编码:

字段标签号在序列化时会被编码为 Varint 格式。Varint 编码是一种可变长度的编码方式,小数值占用的字节数更少。

Varint 编码的规则:

如果数值小于 128,占用 1 个字节。

如果数值大于等于 128,会占用多个字节(每个字节的最高位为 1,最后一个字节的最高位为 0)。

字段标签号的计算:

在 Protobuf 中,字段标签号会与字段类型信息结合,形成一个 Key,用于标识字段。
Key 的计算公式为:Key = (FieldNumber << 3) | WireType

<<3称为 左移运算符(Left Shift Operator),它将一个二进制数的所有位向左移动指定的位数,并在右侧填充零。具体来说,<<3 表示将一个数的二进制表示向左移动 3 位。

也就是说,左移 n 位的效果相当于将原数乘以2^n

其中,FieldNumber 是字段的标签号,WireType 是字段类型的编码(例如,0 表示 Varint 类型,2 表示 Length-Delimited 类型等)。

在这里插入图片描述

| WireType 是指 加上这个数值,比如:Key=(FieldNumber×8)+WireType

也就是标签号为 15 的字段,Key = (15 << 3) | 0 = 120

这些值都小于 128,因此可以使用 1 个字节 来表示。

因为 FieldNumber 是一个整数,而 WireType 的范围是 0 到 7,所以 FieldNumber 需要左移 3 位(即乘以 8),以便为 WireType 留出低 3 位的空间(这样就刚好能够容纳0-7,从二进制的角度来说)。这样,Key 值可以同时包含字段编号和字段类型的信息。


可能有很多人很好奇,1个字节应该可以表示0-255,而不是128.这里我们继续来看看。

在计算机中,一个字节(Byte)由 8 个位(Bit)组成。每个位可以是 0 或 1,因此一个字节可以表示 2^8=256 种不同的值,范围从 0 到 255。

但是在Protobu f的 Varint 编码中,一个字节可以表示的最大数值是 127,而不是 255。这是因为 Varint 编码使用最高位(即第 8 位)作为 继续位(Continuation Bit),用于指示是否还有更多的字节跟随。

如果最高位为 0,表示该字节是最后一个字节;如果最高位为 1,表示后面还有更多的字节。

所以当表示127的时候,就是 0111 1111 ,也就是120+7=127

在二进制中,1000 0000 表示的十进制数值是 128。但在 Protobuf 的 Varint 编码中,这个二进制数的最高位是 1,表示它不是最后一个字节,后面还有更多的字节。因此,1000 0000 在 Varint 编码中表示的数值是 128,但它是多字节序列的一部分,而不是单独的一个字节。也就是它表示一个数值为 128 的多字节序列的开始

那么,1000 0000 0000 0000为128吗?并不是。

再来总结下Varint编码的规则:每个字节的低 7 位用于存储数据,每个字节的最高位(第 8 位)用于表示是否还有后续字节:如果最高位是 1,表示后面还有更多字节。如果最高位是 0,表示这是最后一个字节。


这也就是为什么说明了 因此,使用 1-15 的标签号可以减少序列化后的数据大小,尤其是在消息中包含大量字段时,这种节省会更明显。这也是为什么 Protobuf 推荐将常用字段的标签号放在 1-15 的范围内。

4. TLV

TLV 是一种编码结构,用于描述数据的组织方式。TLV 是 Tag-Length-Value 的缩写,表示数据由三部分组成。

Tag(标签):用于标识字段的编号和类型。在 Protobuf 中,Tag 是由字段编号(field number)和线缆类型(wire type)组合而成的,通过公式 (field_number << 3) | wire_type 编码。

Length(长度)表示 Value 部分的长度。对于某些数据类型(如字符串、嵌套消息等,即string、bytes、embedded messages),Length 是必要的;而对于一些固定长度的类型(如 int32、fixed64 等),Length 可能会被省略。

Value(值):是实际存储的数据内容

比如

message Person {int32 id = 1;string name = 2;
}

对应的实例为

id: 123
name: "Alice"

其二进制编码可能如下:

08 7B:08 是 Tag(字段编号 1,类型为 VARINT),7B 是 Value(123 的 Varint 编码),int类型不需要显示指定长度。

对于存储Varint编码数据,就不需要存储字节长度 Length,所以实际上Protocol Buffer的存储方式是 T - V;

12 05 41 6C 69 63 65:12 是 Tag(字段编号 2,类型为 LEN),05 是 Length(5,表示字符串长度),41 6C 69 63 65 是 Value(字符串 “Alice” 的 UTF-8 编码)。

若Protocol Buffer采用其他编码方式(如LENGTH_DELIMITED)则采用T - L - V


Protobuf的TLV编码

Protobuf 在将数据转换成二进制时,会对字段和类型重新编码,减少空间占用。它采用 TLV 格式来存储编码后的数据。TLV 也是就是 Tag-Length-Value ,是一种常见的编码方式,因为数据其实都是键值对形式,所以在 TAG 中会存储对应的字段和类型信息,Length 存储内容的长度,Value 存储具体的内容。

上面我们讲过,比如类型信息标记,比如 int32 怎么标记,因为类型个数有限,所以 Protobuf 规定了每个类型对应的二进制编码,比如 int32 对应二进制 000,string 对应二进制 010,这样就可以只用三个比特位存储类型信息。

这种编码方式可以在数据值比较小的情况下,只使用一个字节来存储数据,以此来提高编码效率。

并且Protobuf 还可以通过采用压缩算法来减少数据传输的大小。比如 GZIP 算法能够将原始数据压缩成更小的二进制格式,从而在网络传输中能够节省带宽和传输时间。Protobuf 还提供了一些可选的压缩算法,如 zlib 和 snappy,这些算法在不同的场景下能够适应不同的压缩需求

比如下面这张图。

在这里插入图片描述
在这里插入图片描述

根据刚刚的公式来解释下。

首先是id的Tag:1<<3 + 2= 10(注意id是string类型) ,也就是 1010,。

然后是name的Tag:2 << 3 + 2 = 18,也就是10010

Length长度就更好理解了,分别是1和2。

如何通过Varint表示300?

在这里插入图片描述

5. 编译Protobuf

使用 Protobuf 提供的编译器,可以将 .proto 文件编译成各种语言的代码文件(如 Java、C++、Python 等)。

在这里插入图片描述
比如下面两种编译代码方式。

protoc --java_out=./java ./resources/addressbook.protoprotoc --go_out=./go

6. 构造消息对象

刚刚我们定义了对应Proto消息对象如下,那么我们应该怎么使用。

syntax = "proto3";// 指定 Protobuf 包名,防止有相同类名的message定义
package goprotobuf;// Go 生成的包路径 可以通过 go_package 选项指定
option go_package = "/";message Person {// =1,=2 作为序列化后的二进制编码中的字段的唯一标签,也因此,1-15 比 16 会少一个字节,所以尽量使用 1-15 来指定常用字段。optional int32 id = 1;optional string name = 2;optional string email = 3;enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2;}message PhoneNumber {optional string number = 1;optional PhoneType type = 2;}repeated PhoneNumber phones = 4;
}message AddressBook {repeated Person people = 1;
}

这里给出对应的Go版本代码方式。

package mainimport ("fmt""log""github.com/wdbyte/protobuf/addressbook" // 假设这是生成的 Go 包路径
)func main() {// 直接构建phoneNumber1 := &addressbook.PhoneNumber{Number: "18388888888",Type:   addressbook.PhoneType_HOME,}person1 := &addressbook.Person{Id:    1,Name:  "www.wdbyte.com",Email: "xxx@wdbyte.com",Phones: []*addressbook.PhoneNumber{phoneNumber1},}addressBook1 := &addressbook.AddressBook{People: []*addressbook.Person{person1},}fmt.Println(addressBook1)fmt.Println("------------------")// 链式构建addressBook2 := &addressbook.AddressBook{People: []*addressbook.Person{{Id:    2,Name:  "www.wdbyte.com",Email: "yyy@126.com",Phones: []*addressbook.PhoneNumber{{Number: "18388888888",Type:   addressbook.PhoneType_HOME,},},},},}fmt.Println(addressBook2)
}

输出如下:

people {id: 1name: "www.wdbyte.com"email: "xxx@wdbyte.com"phones {number: "18388888888"type: HOME}
}------------------
people {id: 2name: "www.wdbyte.com"email: "yyy@126.com"phones {number: "18388888888"type: HOME}
}

参考文章:
1、https://blog.csdn.net/carson_ho/article/details/70568606/?ops_request_misc=&request_id=&biz_id=102&utm_term=Varint%E7%BC%96%E7%A0%81%E5%A6%82%E4%BD%95%E8%A1%A8%E7%A4%BA128%EF%BC%9F&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-5-70568606.142^v101^pc_search_result_base5&spm=1018.2226.3001.4187
2、https://segmentfault.com/a/1190000043775488#item-4-5

相关文章:

Protobuf原理与序列化

本文目录 1. Protobuf介绍2. Protobuf的优势3. 编写Protobuf头部全局定义消息结构具体定义字段类型定义标签号Base128编码 4. TLVProtobuf的TLV编码如何通过Varint表示300&#xff1f; 5. 编译Protobuf6. 构造消息对象 前言&#xff1a;之前写项目的时候只是简单用了下Protobuf…...

Redis|事务

文章目录 是什么能干嘛Redis 事务 VS 数据库事务怎么玩小总结 是什么 首先回想一下什么是数据库的事务&#xff1f;数据库事务是指作为单个逻辑单元执行的一系列操作&#xff0c;具备以下四个关键特性&#xff08;ACID&#xff09;&#xff1a; 原子性&#xff08;Atomicity&am…...

树莓百度百科更新!宜宾园区业务再添新篇

树莓集团宜宾园区业务不断拓展&#xff0c;主要体现在以下几个方面&#xff1a; 产业布局 -聚焦数字经济核心领域&#xff1a;涵盖软件开发、人工智能、大数据等&#xff0c;吸引众多上下游企业入驻&#xff0c;形成从芯片研发、软件开发到系统集成的完整产业链条。 -推进“双…...

设计模式教程:模板方法模式(Template Method Pattern)

一、概述 模板方法模式&#xff08;Template Method Pattern&#xff09; 是一种行为型设计模式&#xff0c;旨在定义一个操作中的算法骨架&#xff0c;而将一些步骤的具体实现延迟到子类中。通过模板方法模式&#xff0c;父类可以不改变算法结构的情况下&#xff0c;让子类重…...

unity学习54:图片+精灵+遮罩mask,旧版文本 text 和新的TMP文本

目录 1 图片 image 1.1 如果直接导入image 1.2 图片 image 和精灵 sprite 1.2.1 继续修改上面的格式 texture type 是default 1.2.2 再次关联到UI的 image 物体上就可以了 1.3 图片和遮罩 mask 1.3.1 创建1个父物体和1个子物体&#xff0c;分别都是image 1.3.2 如果父…...

【Java项目】基于Spring Boot的校园闲置物品交易网站

【Java项目】基于Spring Boot的校园闲置物品交易网站 技术简介&#xff1a;采用Java技术、Spring Boot框架、MySQL数据库等实现。 系统简介&#xff1a;校园闲置物品交易网站是一个典型的管理系统&#xff0c;主要功能包括管理员&#xff1a;首页、个人中心、用户管理、商品类…...

网页制作08-html,css,javascript初认识のhtml使用框架结构,请先建立站点!

框架一般由框架集和框架组成。 框架集就像一个大的容器&#xff0c;包括所有的框架&#xff0c;是框架的集合。 框架是框架集中一个独立的区域用于显示一个独立的网页文档。 框架集是文件html&#xff0c;它定义一组框架的布局和属性&#xff0c;包括框架的数目&#xff0c;框架…...

DeepSeek-R1:通过强化学习激励大语言模型的推理能力

摘要 本文介绍了我们的第一代推理模型&#xff0c;DeepSeek-R1-Zero 和 DeepSeek-R1。DeepSeek-R1-Zero 是通过大规 模强化学习&#xff08;RL&#xff09;训练的模型&#xff0c;在没有使用监督微调&#xff08;SFT&#xff09;这个前置步骤的情况下&#xff0c;展示了卓越的推…...

hbase笔记总结1

hbase是nosql的一种&#xff0c;非关系型数据库&#xff0c;not only sql&#xff0c;可处理大规模、高并发的数据&#xff0c;是web2.0以后的产物hbase的扩展性和灵活性更好&#xff0c;而且筛选能力相较于MySQL更优nosql的四大特点&#xff1a; 灵活的数据模型 &#xff08;1…...

关于C++中static_cast、const_cast、dynamic_cast的简单介绍

在C中&#xff0c;static_cast、const_cast 和 dynamic_cast 是用于类型转换的关键字&#xff0c;它们的行为和适用场景有显著区别。以下是它们的核心差异和用法总结&#xff1a; 1. static_cast 用途 用于明确且安全的类型转换&#xff0c;通常用于编译时已知类型关系的场景…...

计算机毕业设计 ——jspssm513Springboot 的小区物业管理系统

作者&#xff1a;程序媛9688 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等。 &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff08;免费咨询指导选题&#xff09;&#xf…...

详解Tomcat下载安装以及IDEA配置Tomcat(2023最新)

目录 步骤一&#xff1a;首先确认自己是否已经安装JDK步骤二&#xff1a;下载安装Tomcat步骤三&#xff1a;Tomcat配置环境变量步骤四&#xff1a;验证Tomcat配置是否成功步骤五&#xff1a;为IDEA配置Tomcat 步骤一&#xff1a;首先确认自己是否已经安装JDK jdk各版本通用安…...

端口映射/内网穿透方式及问题解决:warning: remote port forwarding failed for listen port

文章目录 需求&#xff1a;A机器是内网机器&#xff0c;B机器是公网服务器&#xff0c;想要从公网&#xff0c;访问A机器的端口方式&#xff1a;端口映射&#xff0c;内网穿透&#xff0c;使用ssh打洞端口&#xff1a;遇到问题&#xff1a;命令执行成功&#xff0c;但是端口转发…...

2024年第十五届蓝桥杯大赛软件赛省赛Python大学A组真题解析

文章目录 试题A: 拼正方形(本题总分:5 分)解析答案试题B: 召唤数学精灵(本题总分:5 分)解析答案试题C: 数字诗意解析答案试题A: 拼正方形(本题总分:5 分) 【问题描述】 小蓝正在玩拼图游戏,他有7385137888721 个2 2 的方块和10470245 个1 1 的方块,他需要从中挑出一些…...

win11编译pytorch cuda128版本流程

Geforce 50xx系显卡最低支持cuda128&#xff0c;torch cu128 release版本目前还没有释放&#xff0c;所以自己基于2.6.0源码自己编译wheel包。 1. 前置条件 1. 使用visual studio installer 安装visual studio 2022&#xff0c;工作负荷选择【使用c的桌面开发】,安装完成后将…...

AI人工智能机器学习之降维和数据压缩

1、概要 本篇学习AI人工智能机器学习之降维和数据压缩&#xff0c;以主成分分析&#xff08;PCA, Principal Component Analysis&#xff09;为例&#xff0c;从代码层面讲述机器学习中的降维和数据压缩。 2、降维和数据压缩 - 简介 在机器学习和数据分析中&#xff0c;降维&…...

EasyExcel 使用指南:基础操作与常见问题

文章目录 1. EasyExcel 简介2. 基础操作2.1. 写入 Excel &#x1f525;2.2. 读取 Excel ✅2.3. 使用模板 &#x1f3a8; 3. 常见问题与解决方案3.1. 处理日期格式 &#x1f4c5;3.2. 数据写入失败&#xff1a;占位符无法匹配 ❌3.3. 内存溢出&#xff1a;大数据量处理 ⚡3.4. 空…...

本地搭建Koodo Reader书库结合内网穿透打造属于自己的移动图书馆

文章目录 前言1. Koodo Reader 功能特点1.1 开源免费1.2 支持众多格式1.3 多平台兼容1.4 多端数据备份同步1.5 多功能阅读体验1.6 界面简洁直观 2. Koodo Reader安装流程2.1 安装Git2.2 安装Node.js2.3 下载koodo reader 3. 安装Cpolar内网穿透3.1 配置公网地址3.2 配置固定公网…...

Mybatis是如何进行分页的?与Mybatis-plus的区别在哪里?

MyBatis 的分页方式及其与 MyBatis-Plus 的区别可以总结如下&#xff1a; MyBatis 的分页实现 逻辑分页&#xff08;内存分页&#xff09; 使用 RowBounds 对象&#xff0c;在查询时传入参数&#xff0c;MyBatis 会在结果集返回后&#xff0c;在内存中手动截取指定范围的数据。…...

MySQL 主从同步配置及操作步骤

主从同步是一种常见的数据复制技术&#xff0c;它通过将主库的数据同步到一个或多个从数据库中来保证数据的一致性。从库通过读取主库的 binlog 文件来获取更新并进行同步。 主从复制的方式有三种&#xff1a; 异步复制&#xff1a;不需要从库确认&#xff0c;主库提交数据后…...

【软考-架构】备战2025软考

新老教材对比 科目1&#xff08;信息系统综合&#xff09;考点详解 科目2&#xff08;系统架构设计案例&#xff09;考点详解 科目3&#xff08;系统架构设计论文&#xff09;考点详解 趋于越来越具体 学习方法推荐 第一阶段 – 基础知识阶段 建议一个半月&#xff1b; 先过…...

基于Spark的电商供应链系统的设计与实现

目录 1.研究背景与意义 2、国内外研究现状 3、相关理论与技术 &#xff08;一&#xff09;分布式计算系统Spark &#xff08;二&#xff09;数据仓库Hive &#xff08;三&#xff09;读取服务器本地磁盘的日志数据Flume &#xff08;四&#xff09;分布式消息队列Kafka …...

DaoCloud 亮相 2025 GDC丨开源赋能 AI 更多可能

2025 年 2 月 21 日至 23 日&#xff0c;上海徐汇西岸&#xff0c;2025 全球开发者先锋大会以 “模塑全球&#xff0c;无限可能” 的主题&#xff0c;围绕云计算、机器人、元宇宙等多元领域&#xff0c;探讨前沿技术创新、应用场景拓展和产业生态赋能&#xff0c;各类专业论坛、…...

基于coze+微信小程序实现图片上传并利用大模型解析

项目截图&#xff1a; 实现代码&#xff08;直接搬去可用&#xff09; 前提&#xff1a;需要填写你的oss配置coze的api授权配置&#xff01;&#xff01;&#xff01; <template><view class"container"><!-- 高斯模糊背景 --><view class&qu…...

CSS 对齐:深入理解与技巧实践

CSS 对齐:深入理解与技巧实践 引言 在网页设计中,元素的对齐是至关重要的。一个页面中元素的对齐方式直接影响到页面的美观度和用户体验。CSS 提供了丰富的对齐属性,使得开发者可以轻松实现各种对齐效果。本文将深入探讨 CSS 对齐的原理、方法和技巧,帮助开发者更好地掌握…...

Dify部署

Dify部署 安装docker 要在CentOS 7上部署Docker社区版&#xff0c;您可以按照以下步骤进行操作&#xff1a; 卸载旧版本的Docker&#xff08;如果有&#xff09;&#xff1a; yum remove docker docker-client docker-client-latest docker-common docker-latest docker-l…...

MyBatis-Plus 对比传统 MyBatis 的优势

在现代的 Java 开发中&#xff0c;MyBatis 和 MyBatis-Plus 都是流行的持久层框架。MyBatis 是一个轻量级的 ORM 框架&#xff0c;帮助开发者通过映射文件或注解方式来执行 SQL 操作。MyBatis-Plus 是在 MyBatis 基础上进行的增强&#xff0c;提供了许多简化和优化功能&#xf…...

被AWS反撸了,试一下能否申请退还

经过来回几轮沟通&#xff0c;已扣的42美金将退回31美金&#xff0c;未扣的16美金将免除扣款。 31美金的具体计算方法我不知道&#xff0c;对方的回复如下&#xff08;是了&#xff0c;AWS的客服是用中文回复的&#xff09;&#xff1a; 我理解此结果可能不完全符合您所期望的…...

基于Spring Boot的产业园区智慧公寓管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

MySQL 事务笔记

MySQL 事务笔记 目录 事务简介事务操作事务四大特性并发事务问题事务隔离级别总结 事务简介 事务&#xff08;Transaction&#xff09;是数据库操作的逻辑单元&#xff0c;由一组不可分割的SQL操作组成。主要用于保证&#xff1a; 多个操作的原子性&#xff08;要么全部成功…...

SpringBoot 使用 spring.profiles.active 来区分不同环境配置

很多时候&#xff0c;我们项目在开发环境和生产环境的配置是不一样的&#xff0c;例如&#xff0c;数据库配置&#xff0c;在开发的时候&#xff0c;我们一般用测试数据库&#xff0c;而在生产环境&#xff0c;我们要用生产数据库&#xff0c;这时候&#xff0c;我们可以利用 p…...

# C# 中堆(Heap)与栈(Stack)的区别

在 C# 中&#xff0c;堆和栈是两种不同的内存分配机制&#xff0c;它们在存储位置、生命周期、性能和用途上存在显著差异。理解堆和栈的区别对于优化代码性能和内存管理至关重要。 1. 栈&#xff08;Stack&#xff09; 1.1 定义 栈是一种后进先出&#xff08;LIFO&#xff0…...

IP---网络类型

这只是IP的其中一块内容-网络类型&#xff0c;IP还有更多内容可以查看IP专栏&#xff0c;前一章内容为访问服务器流程&#xff0c;可通过以下路径查看IP----访问服务器流程-CSDN博客&#xff0c;欢迎指正 2.网络类型 网络类型---根据二层&#xff08;数据链路层&#xff09;所…...

jQuery UI API 文档

jQuery UI API 文档 引言 jQuery UI 是一个基于 jQuery 的用户界面库,它提供了丰富的交互式组件和效果,使得网页开发变得更加简单和高效。本文档旨在为开发者提供全面的 jQuery UI API 信息,帮助您更好地理解和应用 jQuery UI。 jQuery UI 简介 什么是 jQuery UI? jQu…...

rust 前端npm依赖工具rsup升级日志

rsup是使用 rust 编写的一个前端 npm 依赖包管理工具&#xff0c;可以获取到项目中依赖包的最新版本信息&#xff0c;并通过 web 服务的形式提供查看、升级操作等一一系列操作。 在前一篇文章中&#xff0c;记录初始的功能设计&#xff0c;自己的想法实现过程。在自己的使用过…...

J-LangChain,用Java实现LangChain编排!轻松加载PDF、切分文档、向量化存储,再到智能问答

Java如何玩转大模型编排、RAG、Agent&#xff1f;&#xff1f;&#xff1f; 在自然语言处理&#xff08;NLP&#xff09;的浪潮中&#xff0c;LangChain作为一种强大的模型编排框架&#xff0c;已经在Python社区中广受欢迎。然而&#xff0c;对于Java开发者来说&#xff0c;能…...

文档识别-C#中英文文档识别接口-PDF文件内容识别API

文档识别接口可满足用户在数字化转型过程中对文档处理的高效、准确需求。翔云文档识别接口以成熟的文字识别技术、自然语言处理技术、图像识别技术为核心&#xff0c;能够将文档上的非可编辑文本转化为可编辑的数据&#xff0c;从而提升信息处理的速度与实现文档数字化管理的准…...

什么是元数据管理?为什么数据治理的第一步是整理元数据?

什么是元数据管理&#xff1f; 以下是关于元数据管理、数据治理从元数据开始的原因以及数据治理逻辑的简单介绍&#xff1a; 元数据管理 元数据是关于数据的数据&#xff0c;它主要描述了数据的定义、来源、关系、质量、用途等信息。比如在一个学生成绩管理系统中&#xff…...

QSplashScreen --软件启动前的交互

目录 QSplashScreen 类介绍 使用方式 项目中使用 THPrinterSplashScreen头文件 THPrinterSplashScreen实现代码 使用代码 使用效果 QSplashScreen 类介绍 QSplashScreen 是 Qt 中的一个类&#xff0c;用于显示启动画面。它通常在应用程序启动时显示&#xff0c;以向用户显…...

react使用react-quill 富文本插件、加入handlers富文本不显示解决办法

可以调整图片大小 quill-image-resize-module-react 加入插件quill-image-resize-module-reactQuill.register("modules/imageResize", ImageResize); // 注册图片缩放富文本配置中加入如下const quildConfig {toolbar: {container: [["bold", "ital…...

基于vue框架的的银生中学图书管理系统c7b4q(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,书籍分类,书籍信息,书籍借阅,书籍归还 开题报告内容 基于Vue框架的的银生中学图书管理系统开题报告 一、项目背景与意义 随着信息技术的飞速发展和教育现代化进程的加快&#xff0c;学校图书管理面临着前所未有的挑战与机遇。银…...

2025年02月27日Github流行趋势

项目名称&#xff1a;aibrix 项目地址url&#xff1a;https://github.com/vllm-project/aibrix 项目语言&#xff1a;Jupyter Notebook 历史star数&#xff1a;2568 今日star数&#xff1a;554 项目维护者&#xff1a;Jeffwan, varungup90, brosoul, nwangfw, kr11 项目简介&am…...

去耦电容的作用详解

在霍尔元件的实际应用过程中&#xff0c;经常会用到去耦电容。去耦电容是电路中装设在元件的电源端的电容&#xff0c;其作用详解如下&#xff1a; 一、基本概念 去耦电容&#xff0c;也称退耦电容&#xff0c;是把输出信号的干扰作为滤除对象。它通常安装在集成电路&#xf…...

Vue.js响应式基础

响应式基础​ API 参考 本页和后面很多页面中都分别包含了选项式 API 和组合式 API 的示例代码。现在你选择的是 组合式 API。你可以使用左侧侧边栏顶部的“API 风格偏好”开关在 API 风格之间切换。 声明响应式状态​ ref()​ 在组合式 API 中,推荐使用 ref() 函数来声明…...

解决Deepseek“服务器繁忙,请稍后再试”问题,基于硅基流动和chatbox的解决方案

文章目录 前言操作步骤步骤1&#xff1a;注册账号步骤2&#xff1a;在线体验步骤3&#xff1a;获取API密钥步骤4&#xff1a;安装chatbox步骤5&#xff1a;chatbox设置 价格方面 前言 最近在使用DeepSeek时&#xff0c;开启深度思考功能后&#xff0c;频繁遇到“服务器繁忙&am…...

Java SSE流式数据前后端实现

#Java SSE流式数据前后端实现 Java后端实现 RestController public class SSEController {GetMapping(value "/sse/stream", produces MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter streamSse() throws InterruptedException, IOException {SseEmitter …...

DeepSeek开源周Day4:三连发!突破 AI 训练瓶颈的立体解决方案,并行计算三剑客DualPipe、EPLB与Profile-data

项目地址&#xff1a; https://github.com/deepseek-ai/DualPipehttps://github.com/deepseek-ai/eplbhttps://github.com/deepseek-ai/profile-data 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (4/5)&#xff01; ​ ​ 一、背景概述 …...

3-1 WPS JS宏工作簿的新建与保存(批量新建工作簿)学习笔记

************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…...

esp8266 rtos sdk开发环境搭建

1. 安装必要的工具 1.1 安装 Git Git 用于从远程仓库克隆代码&#xff0c;你可以从Git 官方网站下载 Windows 版本的安装程序。安装过程中可保持默认设置&#xff0c;安装完成后&#xff0c;在命令提示符&#xff08;CMD&#xff09;或 PowerShell 中输入git --version&#…...

Pycharm使用matplotlib出现的问题(1、不能弹出图表 2、图表标题中文不显示)

Pycharm使用matplotlib出现的问题 问题1&#xff1a;Pycharm调试时出现&#xff1a;AttributeError: module backend_interagg has no attribute FigureCanvas. Did you mean: FigureCanvasAgg? 排查原因&#xff1a;可能是由于matplotlib后端设置不正确或与运行环境不兼容引…...