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

数据序列化协议 Protobuf 3 介绍(Go 语言)

Protobuf 3 入门

1. 什么是序列化?

1.1 概念

序列化(Serialization 或 Marshalling) 是指将数据结构或对象的状态转换成可存储或传输的格式。反向操作称为反序列化(Deserialization 或 Unmarshalling),它的作用是将序列化的数据恢复成原始的数据结构或对象。

简单来说,序列化就像“打包”,反序列化就像“解包”

2.1 为什么需要序列化?

在计算机系统中,数据通常是以内存中的对象(如 structclass)形式存在的,而内存数据不能直接在不同程序之间传输,必须先转换成可存储或可传输的格式。序列化的主要用途包括:

  1. 数据存储:将数据保存到文件、数据库等,例如:
    • 日志文件
    • 配置文件(如 JSON、YAML)
    • 持久化存储(如 Redis、MongoDB)
  2. 数据传输:在不同进程或网络之间传输数据,例如:
    • 前端和后端通信(Web API)
    • 微服务之间的通信
    • 远程调用(RPC,如 gRPC)
  3. 数据缓存:比如将复杂的对象序列化后存入 Redis,提高访问速度。
  4. 跨语言兼容:不同编程语言的数据结构不一样,序列化后可以在不同语言之间传输数据。

3.1 序列化的方式

不同的序列化格式适用于不同的应用场景,常见的格式包括:

格式特点可读性序列化速度数据大小适用场景
JSON文本格式,广泛使用可读适中较大Web API,前端后端通信
XML结构化文本,标签冗余可读早期 Web API,配置文件
YAML结构更简洁,适合人阅读可读适中较大配置文件(Kubernetes、Docker)
ProtobufGoogle 开发的高效二进制格式不可读微服务、gRPC、高性能应用
MessagePack类似 JSON,但体积更小不可读移动端、嵌入式系统
ThriftFacebook 开发的高效序列化格式不可读分布式系统,RPC
Avro适用于大数据(如 Hadoop)不可读适中大数据处理
BSONMongoDB 的序列化格式不可读适中适中MongoDB 数据存储

2. 什么是 Protobuf?

2.1 概念

Protobuf(Protocol Buffers)是 Google 开发的一种高效、跨平台、可扩展数据序列化协议。它可以将数据转换为紧凑的二进制格式,用于不同系统之间进行高效的数据传输和存储。

简单理解:

  • 它类似于 JSON,但比 JSON 体积更小、速度更快。
  • 它类似于 XML,但格式更紧凑、解析更高效。
  • 它适用于微服务、RPC(远程调用)、数据存储等高性能场景。

2.2 为什么使用 Protobuf?

特点ProtobufJSONXML
格式二进制文本文本
体积最小较大最大
解析速度最快一般最慢
可读性不可读可读可读
跨语言支持
支持 RPC是(gRPC)

如果你的项目涉及:

  • 高性能数据通信(微服务、RPC、物联网、游戏服务器)
  • 跨语言数据传输(Go、Java、Python、C++、Rust 等)
  • 大规模数据存储(日志、数据库、缓存)

那么 Protobuf 是比 JSON、XML 更好的选择

2.3 Protobuf 的使用场景

  1. 微服务通信(gRPC)
    • 适用于 Go、Java、Python、C++ 等语言的微服务之间高效通信。
    • 结合 gRPC 使用,可以比传统 REST API 更快。
  2. 数据存储
    • 存储日志、缓存数据(如存入 Redis)时,Protobuf 体积小,能节省存储空间
  3. 跨语言数据交换
    • 由于 Protobuf 支持多种编程语言,可以在不同语言的系统之间进行高效数据传输。
  4. 移动端和 IoT(物联网)
    • 移动端和 IoT 设备通常带宽和存储受限,Protobuf 适用于传输小体积数据,提高性能。

3. 简单解释 Protobuf 例子

3.1 Protobuf 文件 simple.proto

syntax = "proto3"; // 使用 proto3 语法message SearchRequest {  // 定义一个数据结构(类似 JSON 对象)string query = 1;      // 搜索关键词(字符串)int32 page_number = 2; // 页码(整数)int32 result_per_page = 3; // 每页返回的结果数(整数)
}

解释

  • syntax = "proto3"; 指定使用 proto3 语法。
  • message SearchRequest 定义了一个数据结构(类似 JSON 对象)。
  • 每个字段的格式:
    • 类型stringint32
    • 字段名称querypage_numberresult_per_page
    • 字段编号123,用于唯一标识字段,不能重复)

3.2 编译 Protobuf 代码

Protobuf 需要编译后才能用于编程语言(Go、Java、Python 等)。 在终端运行:

protoc --go_out=. simple.proto
  • protoc 是 Protobuf 编译器
  • --go_out=. 表示生成 Go 代码,并存放在当前目录
  • simple.proto 是需要编译的 Protobuf 文件

不同语言对应的参数:

语言编译参数
C++--cpp_out=.
Java--java_out=.
Python--python_out=.
C#--csharp_out=.
Rust--rust_out=.

最终会生成 simple.pb.go,这个文件包含 Go 代码,用于操作 SearchRequest 结构。

3.3 生成的 Go 代码

编译后会生成如下 Go 结构:

type SearchRequest struct {Query         string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"`PageNumber    int32  `protobuf:"varint,2,opt,name=page_number,json=pageNumber,proto3" json:"page_number,omitempty"`ResultPerPage int32  `protobuf:"varint,3,opt,name=result_per_page,json=resultPerPage,proto3" json:"result_per_page,omitempty"`
}

解释

  • SearchRequeststruct,对应 .proto 文件中的 message SearchRequest
  • QueryPageNumberResultPerPage 变量对应 .proto 里的字段。
  • protobuf:"..." 里的信息用于 Protobuf 序列化和解析。

3.4 如何使用这个 Go 结构

package mainimport ("fmt""google.golang.org/protobuf/proto"
)func main() {// 创建 SearchRequest 实例request := &SearchRequest{Query:         "golang protobuf",PageNumber:    1,ResultPerPage: 10,}// **序列化**data, _ := proto.Marshal(request)// **反序列化**newRequest := &SearchRequest{}proto.Unmarshal(data, newRequest)fmt.Println(newRequest) // 输出: {Query:golang protobuf PageNumber:1 ResultPerPage:10}
}

解释

  1. 创建 SearchRequest 结构,并填充数据。
  2. 使用 proto.Marshal(request) 序列化,转换成二进制格式(适合网络传输)。
  3. 使用 proto.Unmarshal(data, newRequest) 反序列化,把二进制恢复成 Go 结构。

4. Protobuf 的数据类型

4.1 标量数据类型(Scalar Types)

Protobuf 提供了一些常见的基本数据类型,对应不同语言的变量类型。

4.1.1 数值类型
Protobuf 类型说明适用场景
int3232 位整数(默认编码)适用于较小的整数
int6464 位整数(默认编码)适用于较大的整数
uint32无符号 32 位整数适用于只能为正数的情况
uint64无符号 64 位整数适用于大数且不允许负数
sint3232 位有符号整数(ZigZag 编码)适用于可能包含负数的整数
sint6464 位有符号整数(ZigZag 编码)适用于包含负数的长整数
fixed3232 位整数(固定长度编码)适用于数值分布较均匀的场景
fixed6464 位整数(固定长度编码)适用于较大的定长整数
sfixed3232 位有符号整数(固定长度编码)适用于负数较多的场景
sfixed6464 位有符号整数(固定长度编码)适用于较大的负数

区别:

  • int32/int64:默认使用 Varint 编码(数据小的时候占用字节更少)。
  • sint32/sint64:使用 ZigZag 编码,负数编码更高效。
  • fixed32/fixed64:使用固定长度存储,适合数值分布均匀的情况。
  • sfixed32/sfixed64:固定长度的有符号整数。
4.1.2 浮点数类型
Protobuf 类型说明适用场景
float32 位浮点数适用于存储小数
double64 位浮点数适用于更高精度的小数

注意:

  • float4 个字节,精度有限。
  • double8 个字节,适用于更高精度计算。
4.1.3 布尔类型
Protobuf 类型说明适用场景
bool布尔值 (true/false)适用于开关、状态等

示例:

message Example {bool is_active = 1; // true or false
}
4.1.4 字符串和字节类型
Protobuf 类型说明适用场景
stringUTF-8 编码的字符串存储文本信息
bytes原始字节数据适用于存储二进制数据(如文件、图片等)

示例:

message Example {string name = 1;bytes file_data = 2;
}

注意:

  • string 只能存储 文本(UTF-8 编码)。
  • bytes 可以存储 任意二进制数据(如图片、视频等)。

4.2 复杂数据类型

4.2.1 数组(Repeated)

使用 repeated 关键字表示 列表/数组

message Example {repeated string hobbies = 1;repeated int32 scores = 2;
}
  • repeated string hobbies = 1; → 表示字符串数组
  • repeated int32 scores = 2; → 表示整数数组

注意

  • 在 Protobuf 3 中,repeated 类型默认是可选的,不需要额外的 optional 关键字。
4.2.2 键值对(Map)

Protobuf 3 提供 map<K, V> 类型来存储键值对

message Example {map<string, int32> scores = 1; // key: string, value: int32
}
  • map<string, int32> 表示 键为字符串,值为整数 的字典。
  • 生成代码后,会转换成 Go 语言的 map[string]int32
4.2.3 枚举类型(Enum)
enum Status {UNKNOWN = 0;  // 枚举必须从 0 开始ACTIVE = 1;INACTIVE = 2;
}message User {Status status = 1;
}
  • enum 只能用于定义固定的值(类似 int)。
  • 第一个枚举值必须是 0,防止解析错误。
4.2.4 嵌套 Message
message Address {string city = 1;string street = 2;
}message Person {string name = 1;Address address = 2; // 直接嵌套 Address
}
  • Person 结构里包含 Address 结构,可以用于复杂数据存储。

4.3 Protobuf 类型与不同语言的对应关系

Protobuf 类型GoJavaPythonC++
int32int32intintint32_t
int64int64longintint64_t
floatfloat32floatfloatfloat
doublefloat64doublefloatdouble
boolboolbooleanboolbool
stringstringStringstrstd::string
bytes[]bytebyte[]bytesstd::string
map<K,V>map[K]VMap<K,V>dictstd::map<K,V>
repeated[]TList<T>liststd::vector<T>

4.4 Protobuf 3 语法示例

syntax = "proto3";message Person {string name = 1;int32 age = 2;bool is_active = 3;repeated string hobbies = 4;map<string, int32> scores = 5;
}

这个 Person 结构包含:

  • string name → 姓名
  • int32 age → 年龄
  • bool is_active → 是否激活
  • repeated string hobbies → 兴趣爱好(数组)
  • map<string, int32> scores → 课程成绩(键值对)

5. Protobuf 其他字段

5.1 Oneof(互斥字段)

5.1.1 什么是 oneof

oneof 关键字用于定义一组互斥字段,即同一时间只能有一个字段被设置。它的作用类似于 C 语言的 union,但比 union 更智能,可以判断当前设置的是哪个字段

5.1.2 为什么要用 oneof

proto3 版本中,所有字段都有默认值,比如:

message Example {int64 id = 1;
}
  • 如果 id 没有被设置,默认值是 0
  • 但如果 id 被显式设置为 0,你就无法判断这个 0 是默认值,还是用户真的设置了 0

oneof 解决了这个问题,因为它提供了一个字段状态检查功能,让你可以判断哪个字段被设置了

5.1.3 oneof 语法
message Response {oneof result {string success_message = 1; // 成功时的消息int32 error_code = 2; // 失败时的错误码}
}
  • oneof 内的字段是互斥的,最多只能设置一个。
  • 如果 success_message 被设置,error_code 就不能被设置,反之亦然。
  • 如果不设置任何字段,oneof 字段为空

适用场景

  • API 响应(成功返回 success_message,失败返回 error_code)。
  • 状态表示(例如订单可能是“待支付”或“已完成”,但不能同时处于这两个状态)。
5.1.4 oneof 在 Go 语言中的使用

Protobuf 生成的 Go 代码会使用 isXxx() 方法 来判断哪个字段被赋值。

示例:Go 代码

package mainimport ("fmt""google.golang.org/protobuf/proto"
)// 假设 Protobuf 生成的 Go 结构如下:
type Response struct {// 这是 oneof 生成的字段Result isResponse_Result `protobuf_oneof:"result"`
}type isResponse_Result interface {isResponse_Result()
}type Response_SuccessMessage struct {SuccessMessage string
}type Response_ErrorCode struct {ErrorCode int32
}// 实现 isResponse_Result 接口
func (*Response_SuccessMessage) isResponse_Result() {}
func (*Response_ErrorCode) isResponse_Result() {}func main() {// **成功时返回 success_message**resp1 := &Response{Result: &Response_SuccessMessage{SuccessMessage: "Operation successful"}}// **失败时返回 error_code**resp2 := &Response{Result: &Response_ErrorCode{ErrorCode: 404}}// 判断是哪个字段被设置switch v := resp1.Result.(type) {case *Response_SuccessMessage:fmt.Println("Success:", v.SuccessMessage)case *Response_ErrorCode:fmt.Println("Error:", v.ErrorCode)}switch v := resp2.Result.(type) {case *Response_SuccessMessage:fmt.Println("Success:", v.SuccessMessage)case *Response_ErrorCode:fmt.Println("Error:", v.ErrorCode)}
}

输出

Success: Operation successful
Error: 404
  • oneof 生成了 isResponse_Result 接口,允许我们判断哪个字段被设置。
  • switch v := resp.Result.(type) 语法用于检查当前 oneof 字段的类型。
5.1.5 oneof 的应用场景
  • REST API / gRPC 响应(成功返回数据,失败返回错误码)
  • 订单状态未支付 / 已支付
  • 用户身份验证邮箱登录 / 手机号登录
  • 存储不同类型的数据文本 / 图片 / 视频

5.2 Reserved(保留字段)

5.2.1 什么是reserved

在 Protobuf 3 中,reserved 关键字用于保留字段编号或名称,防止将来代码演进时误用已删除的字段
这可以避免 API 变更时的兼容性问题,确保旧数据不会被错误解析。

5.2.2 为什么需要 reserved

当你删除或修改字段时,如果不使用 reserved,那么:

  1. 未来新添加的字段可能意外复用旧的字段编号,导致数据解析出错。
  2. 旧数据仍然可能使用被删除的字段,导致意外行为。
5.2.3 reserved 语法

你可以用 reserved 关键字保留字段编号或名称,防止后续被重新使用。

保留字段编号

message User {reserved 2, 4 to 6; // 不能再使用编号 2、4、5、6
}
  • 以后不能再使用 2、4、5、6 作为字段编号
  • 如果后续尝试用 field = 2;,编译时会报错。

保留字段名称

message User {reserved "old_name", "deprecated_field"; // 不能再使用这些字段名
}
  • 以后不能再使用 “old_name” 和 “deprecated_field” 作为字段名。

同时保留编号和名称

message User {reserved 2, 4 to 6;reserved "old_name", "deprecated_field";
}
  • 这样可以同时保留编号和字段名称,防止意外复用。
5.2.4 reserved 作用
  • 避免旧数据解析错误:如果编号被误用,旧数据可能被错误解析。
  • 防止 API 兼容性问题:如果 API 变更,保留字段可以确保旧客户端不会收到无效数据。
  • 让代码更可维护:明确告诉后续开发者哪些字段不能使用

5.3 Any(存储任意数据)

5.3.1 什么是 Any

Any 是 Protobuf 3 提供的一种特殊类型,允许存储任意类型的 Protobuf 消息,适用于动态数据场景。
它可以在不修改 .proto 结构的情况下,支持不同类型的数据,类似于 JSON 里的 objectmap<string, any>

5.3.2 Any 的作用
  • 存储动态数据:如果一个字段的类型可能变化(例如可能是 UserOrder),可以使用 Any 而不需要改 .proto 文件。
  • 实现灵活的 API 设计:适用于插件系统、事件系统、日志系统,让不同的子系统传递不同的数据结构。
  • 避免频繁修改 Protobuf 定义:当不同的客户端需要传输不同的数据类型时,使用 Any 可以减少 API 变更的影响。
5.3.3 Any 的基本用法

(1)导入 Any 类型

Any 需要导入 google/protobuf/any.proto

import "google/protobuf/any.proto"; // 引入 Any 类型message Response {string message = 1; google.protobuf.Any data = 2; // 存储任意类型
}
  • message 是普通字段,存储文本信息。
  • dataAny 类型,可以存储任何 Protobuf 消息

(2)嵌套不同的消息

假设你有两种不同的消息 UserOrder

message User {string name = 1;int32 age = 2;
}message Order {int32 order_id = 1;double price = 2;
}message Response {string message = 1;google.protobuf.Any data = 2; // 可以存储 User 或 Order
}
  • data 字段可以存储 UserOrder,而不需要修改 Response 结构。
  • 这样,Response 可以在不同场景下使用,不受数据类型影响
5.3.4 Any 在 Go 语言中的使用

(1)安装 Protobuf 依赖

在 Go 代码中,需要 protoanypb(处理 Any 类型):

go get google.golang.org/protobuf/proto
go get google.golang.org/protobuf/types/known/anypb

(2)Go 代码示例

package mainimport ("fmt""google.golang.org/protobuf/proto""google.golang.org/protobuf/types/known/anypb"
)// 定义 User 和 Order 结构
type User struct {Name stringAge  int32
}type Order struct {OrderId int32Price   float64
}// Response 结构,包含 Any 字段
type Response struct {Message stringData    *anypb.Any
}func main() {// 创建 User 结构user := &User{Name: "Alice", Age: 25}// 将 User 结构封装到 Any 里anyData, _ := anypb.New(user)// 创建 Response 并存储 User 数据resp := &Response{Message: "User data",Data:    anyData,}// **序列化**data, _ := proto.Marshal(resp)// **反序列化**newResp := &Response{}proto.Unmarshal(data, newResp)// **解析 Any 字段**newUser := &User{}newResp.Data.UnmarshalTo(newUser)fmt.Println("Message:", newResp.Message)fmt.Println("User Name:", newUser.Name, "Age:", newUser.Age)
}

(3)Go 代码解释

  1. 封装数据:
    • 使用 anypb.New(user)User 结构转换成 Any 类型。
  2. 序列化 Response
    • 使用 proto.Marshal(resp) 进行序列化,便于存储或传输。
  3. 反序列化 Response
    • 使用 proto.Unmarshal(data, newResp) 解析 Response 结构。
  4. 解析 Any 数据:
    • newResp.Data.UnmarshalTo(newUser) 解析 Any 字段,恢复 User 结构。

6. Protobuf 编码原理

Protobuf 使用高效的二进制格式来存储和传输数据,其中最关键的编码方式之一是 Varint(变长整数编码)。它的核心思想是:

  • 数值越小,占用字节越少
  • 数值越大,占用字节越多
  • 高效存储,减少带宽消耗

6.1 什么是 Varint?

Varint(变长整数编码) 是一种特殊的编码方式,它可以使用 1 到 N 个字节 表示整数。

  • 小数占用更少字节(如 1 只需要 1 个字节)。
  • 大数会自动扩展到多个字节(如 300 需要 2 个字节)。

6.2 Varint 编码规则

  1. 每个字节的最高位(MSB,Most Significant Bit)是“是否还有后续字节的标志”
    • 最高位为 0:表示这是最后一个字节。
    • 最高位为 1:表示后面还有字节。
  2. 剩下的 7 位存储数据(低位优先,LSB)。

6.3 具体示例

(1)数字 1 的 Varint 编码

0000 0001  (只有 1 个字节)
  • 最高位 0:表示这是最后一个字节。
  • 其余 7 位 000 0001(= 1)

存储方式:

[0000 0001]  → 1 字节

(2)数字 300 的 Varint 编码

先看二进制表示:

300 = 100101100(9 位)

需要拆成 7 位 + 剩余部分

低 7 位: 0101100  → 0x2C(44)
高 2 位: 0000010  → 0x02(2)
  • 第一字节:1010 1100(0xAC)
    • 最高位 1(表示后面还有字节)。
    • 剩余 7 位存 010 1100(= 44)。
  • 第二字节:0000 0010(0x02)
    • 最高位 0(表示这是最后一个字节)。
    • 剩余 7 位存 000 0010(= 2)。

最终编码

[1010 1100]  [0000 0010]  → 2 字节(0xAC 0x02)

6.4 Wire Type(数据类型编码)

Protobuf 数据存储为 键值对(key-value) 形式,每个字段的 key 也需要编码。
字段的 key字段编号 + Wire Type 组成。

Wire Type作用
Varint0变长整数(int32, int64, bool, enum
Fixed64164 位定长(double, fixed64, sfixed64
Length-delimited2变长数据(string, bytes, message, repeated
Start group3已废弃(用于嵌套数据)
End group4已废弃
Fixed32532 位定长(float, fixed32, sfixed32

存储格式

[字段编号 << 3] | [Wire Type]  [数据]

字段编号左移 3 位,低 3 位存 Wire Type

6.5 例子:Protobuf 编码解析

假设 Person 结构如下:

message Person {int32 id = 1;        // 1 字段编号string name = 2;     // 2 字段编号
}

数据:

{"id": 150,"name": "Alice"
}

编码过程

  1. 字段 id = 150

    • 字段编号 = 1
    • Wire Type = 0(Varint)
    • key = (1 << 3) | 0 = 0000 1000 (0x08)
    • 150 的 Varint 编码:1001 0110 0000 0001(0x96 0x01)

    最终存储

    [0x08]  [0x96 0x01]  (字段编号 1,Varint)
    
  2. 字段 name = "Alice"

    • 字段编号 = 2
    • Wire Type = 2(Length-delimited,字符串)
    • key = (2 << 3) | 2 = 0001 0001 (0x12)
    • "Alice" = 5 个字节(0x41 0x6C 0x69 0x63 0x65

    最终存储

    [0x12]  [0x05]  [0x41 0x6C 0x69 0x63 0x65]
    

6.6 解析 Protobuf 二进制数据

假设收到如下二进制数据:

08 96 01 12 05 41 6C 69 63 65

逐字节解析:

  1. 08 = 0000 1000(字段编号 1,Wire Type 0,Varint)
  2. 96 01 = 150(Varint 解码)
  3. 12 = 0001 0010(字段编号 2,Wire Type 2,字符串)
  4. 05 = 长度 5
  5. 41 6C 69 63 65 = "Alice"

最终解析为:

{"id": 150,"name": "Alice"
}

相关文章:

数据序列化协议 Protobuf 3 介绍(Go 语言)

Protobuf 3 入门 1. 什么是序列化&#xff1f; 1.1 概念 序列化&#xff08;Serialization 或 Marshalling&#xff09; 是指将数据结构或对象的状态转换成可存储或传输的格式。反向操作称为反序列化&#xff08;Deserialization 或 Unmarshalling&#xff09;&#xff0c;它…...

从芯片到光网络:解密平面光波导技术(PLC)核心优势

关键词&#xff1a;PLC、OFDR、光链路检测 平面光波导技术&#xff08;Planar Lightwave Circuit, PLC&#xff09;是一种基于平面波导结构的光学器件制造技术。它通过在平面基底上制作光波导&#xff0c;实现光信号的传输、分路、耦合、调制等功能。PLC技术的核心在于利用光波…...

5分钟快速搭建一个 SpringBoot3 + MyBatis-Plus 工程项目

环境 idea 2023.3.5 jdk 17 mysql 8 创建SpringBoot工程 创建SpringBoot工程&#xff0c;这里有两种方式可选&#xff0c;一种是使用idea提供的Spring Initializr自动创建&#xff0c;一种是通过Maven Archetype手动创建 自动创建SpringBoot工程 使用Spring Initializr创建…...

如何判断https使用了哪个版本的TLS?

互联网各领域资料分享专区(不定期更新): Sheet 正文 一、使用浏览器开发者工具(适合普通用户) 1. Google Chrome 打开目标网站(如 https://example.com)。点击地址栏左侧的 锁形图标。选择 「连接是安全的」 → 「证书信息」。在证书详情中,查看 「技术详细信息」 或 「…...

如何在 NocoBase 中实现 CRM 的线索转化

1. 引言 本教程将一步一步地引导您如何在 NocoBase 中实现 CRM 的商机转化&#xff08;Opportunity Conversion&#xff09;功能。我们将介绍如何创建所需的 collections&#xff08;数据表&#xff09;、配置数据管理页面、设计转化流程以及设置关联管理&#xff0c;从而帮助…...

StarRocks-fe工程在Cursor中不能识别为Java项目

SR简介 StarRocks 是一款高性能分析型数据库&#xff0c;支持实时、多维度、高并发的数据分析。本指南旨在解决在使用 VSCode 或 Cursor 开发 StarRocks 后端项目时遇到的模块识别问题。 问题描述 使用 Cursor 或 VSCode 打开 StarRocks 的后端工程 fe 时&#xff0c;spark-…...

影刀RPA开发拓展--SQL常用语句全攻略

前言 SQL&#xff08;结构化查询语言&#xff09;是数据库管理和操作的核心工具&#xff0c;无论是初学者还是经验丰富的数据库管理员&#xff0c;掌握常用的 SQL 语句对于高效管理和查询数据都至关重要。本文将系统性地介绍最常用的 SQL 语句&#xff0c;并为每个语句提供详细…...

05类加载机制篇(D6_方法调用和方法执行)

目录 一、字节码指令集 二、基本数据类型 1. 加载和存储指令 2. const系列 3. push系列 4. ldc系列 5. load系列 load系列A load系列B 6. store系列 store系列A store系列B 7. pop系列 8. 栈顶元素数学操作及移位操作系列 9. 运算指令 10. 类型转换指令 11. 宽…...

视音频数据处理入门:颜色空间(二)---ffmpeg

目录 概述 流程 相关流程 初始化方法 初始化代码 转换方法 转换代码 释放方法 整体代码介绍 代码路径 概述 本篇简单说一下基于FFmpeg的libswscale的颜色空间转换&#xff1b;Libswscale里面实现了各种图像像素格式的转换&#xff0c;例如&#xff1a;YUV与RGB之间的…...

从零开始:H20服务器上DeepSeek R1 671B大模型部署与压力测试全攻略

前言 最近&#xff0c;我有幸在工作中接触到了DeepSeek R1 671B模型&#xff0c;这是目前中文开源领域参数量最大的高质量模型之一。DeepSeek团队在2024年推出的这款模型&#xff0c;以其惊人的6710亿参数量和出色的推理性能&#xff0c;引起了业界广泛关注。 作为一名AI基础…...

【FAQ】HarmonyOS SDK 闭源开放能力 —Map Kit(5)

1.问题描述&#xff1a; 提供两套标准方案&#xff0c;可根据体验需求选择&#xff1a; 1.地图Picker(地点详情) 用户体验&#xff1a;①展示地图 ②标记地点 ③用户选择已安装地图应用 接入文档&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guide…...

Leetcode 3469. Find Minimum Cost to Remove Array Elements

Leetcode 3469. Find Minimum Cost to Remove Array Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3469. Find Minimum Cost to Remove Array Elements 1. 解题思路 这一题我没啥特别好的思路&#xff0c;就只能动态规划了&#xff0c;倒是也能过&#xff0c;不过总…...

Excel的行高、列宽单位不统一?还是LaTeX靠谱

想要生成田字格、米字格、带拼音标准&#xff0c;方便小学生书法和练字。Word&#xff0c;Excel之类所见即所得是最容易相当的方式。但它们处理带田字格之类背景时&#xff0c;如果没有专用模板、奇奇怪怪的插件&#xff0c;使用起来会碰到各种问题。比如&#xff0c;Word里面用…...

(新版本onenet)stm32+esp8266/01s mqtt连接onenet上报温湿度和远程控制(含小程序)

物联网实践教程&#xff1a;微信小程序结合OneNET平台MQTT实现STM32单片机远程智能控制 远程上报和接收数据——汇总 前言 之前在学校获得了一个新玩意&#xff1a;ESP-01sWIFI模块&#xff0c;去搜了一下这个小东西很有玩点&#xff0c;远程控制LED啥的&#xff0c;然后我就想…...

告别GitHub连不上!一分钟快速访问方案

一、当GitHub抽风时&#xff0c;你是否也这样崩溃过&#xff1f; &#x1f621; npm install卡在node-sass半小时不动&#x1f62d; git clone到90%突然fatal: early EOF&#x1f92c; 改了半天hosts文件&#xff0c;第二天又失效了... 根本原因&#xff1a;传统代理需要复杂…...

迷你世界脚本对象库接口:ObjectLib

对象库接口&#xff1a;ObjectLib 迷你世界 更新时间: 2023-04-26 20:21:09 具体函数名及描述如下: 序号 函数名 函数描述 1 getAreaData(...) 获取区域数据 2 getPositionData(...) 获取位置数据 3 getLivingData(...) 获取生物数据 4 getItemDat…...

数据库事务、乐观锁及悲观锁

参考&#xff1a;node支付宝支付及同步、异步通知、主动查询支付宝订单状态 以下容结合上述链接查看 1. 什么是数据库事务&#xff1f; 1.1. 连续执行数据库操作 在支付成功后&#xff0c;我们在自定义的paidSuccess里&#xff0c;依次更新了订单状态和用户信息。也就说这里…...

蓝桥王国--dij模板

#include <bits/stdc.h> // 万能头 using namespace std; typedef pair<long long ,int> PII; int n,m; long long d[300011]; struct edge///邻接表 {int v;long long w; }; int vis[300011]; vector<edge> mp[300011];///邻接表 void dij(int s)///dij单源…...

Java基础关键_017_集合(一)

目 录 一、概述 二、Collection 关系结构 1.概览 2.说明 三、Collection 接口 1.通用方法 &#xff08;1&#xff09;add(E e) &#xff08;2&#xff09;size() &#xff08;3&#xff09;addAll(Collection c) &#xff08;4&#xff09;contains(Object o) &#…...

Rust编程实战:Rust实现简单的Web服务,单线程性能问题

知识点 tcp 服务多线程处理 实现功能 启动web服务&#xff0c;访问链接获取页面内容。 单线程web服务 TcpListener 使用 TcpListener 开启服务端口 let listener TcpListener::bind("127.0.0.1:7878").unwrap();处理客户端连接&#xff1a; for stream in lis…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...