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

【跟小嘉学 Rust 编程】二十九、Rust 中的零拷贝序列化解决方案(rkyv)

系列文章目录

【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据
【跟小嘉学 Rust 编程】六、枚举和模式匹配
【跟小嘉学 Rust 编程】七、使用包(Packages)、单元包(Crates)和模块(Module)来管理项目
【跟小嘉学 Rust 编程】八、常见的集合
【跟小嘉学 Rust 编程】九、错误处理(Error Handling)
【跟小嘉学 Rust 编程】十一、编写自动化测试
【跟小嘉学 Rust 编程】十二、构建一个命令行程序
【跟小嘉学 Rust 编程】十三、函数式语言特性:迭代器和闭包
【跟小嘉学 Rust 编程】十四、关于 Cargo 和 Crates.io
【跟小嘉学 Rust 编程】十五、智能指针(Smart Point)
【跟小嘉学 Rust 编程】十六、无畏并发(Fearless Concurrency)
【跟小嘉学 Rust 编程】十七、面向对象语言特性
【跟小嘉学 Rust 编程】十八、模式匹配(Patterns and Matching)
【跟小嘉学 Rust 编程】十九、高级特性
【跟小嘉学 Rust 编程】二十、进阶扩展
【跟小嘉学 Rust 编程】二十一、网络编程
【跟小嘉学 Rust 编程】二十三、Cargo 使用指南
【跟小嘉学 Rust 编程】二十四、内联汇编(inline assembly)
【跟小嘉学 Rust 编程】二十五、Rust命令行参数解析库(clap)
【跟小嘉学 Rust 编程】二十六、Rust的序列化解决方案(Serde)
【跟小嘉学 Rust 编程】二十七、Rust 异步编程(Asynchronous Programming)
【跟小嘉学 Rust 编程】二十八、Rust中的日期与时间
【跟小嘉学 Rust 编程】二十九、Rust 中的零拷贝序列化解决方案(rkyv)

文章目录

  • 系列文章目录
    • @[TOC](文章目录)
  • 前言
  • 一、rkyv介绍
  • 二、零拷贝反序列化(Zero-Copy Deserialization)
    • 2.1、零拷贝反序列化(Zero-Copy Deserialization)
    • 2.2、部分零拷贝(Partial Zero-Copy)
    • 2.3、完全零拷贝(Total Zero-Copy)
  • 三、体系结构
    • 3.1、相对指针(Relative pointers)
    • 3.2、存档(Archive)
    • 3.3、序列化(Serialize)
    • 3.4、反序列化(Deserialize)
    • 3.5、对齐(Alignment)
  • 四、rkyv 使用
  • 总结

前言

本章节讲解 Rust的另外一个序列化的解决方案:零拷贝序列化解决方案(rkyv库)

主要教材参考 《The Rust Programming Language》
主要教材参考 《Rust For Rustaceans》
主要教材参考 《The Rustonomicon》
主要教材参考 《Rust 高级编程》
主要教材参考 《Cargo 指南》
主要教材参考 《Rust 异步编程》


一、rkyv介绍

rkyv 是 Dusk network 赞助的第一个 ZKP(Zero-Knowledge Recrusion)研究项目

代码仓库地址:https://github.com/rkyv/rkyv

rkyv 是纯 Rust 语言实现的 零拷贝序列化框架,它的主要特征就是零拷贝。 rkyv 允许在代码中定义所有序列化类型,并且可以序列化其他类型无法序列化的各种类型。

rkyv 的目的就是为了提高性,实现这一目标的方式,在内存使用、正确性、安全性方面取得进展。

如果你熟悉其他序列化框架以及传统序列化的工作原理会有帮助,但是对于理解 rkyv 的工作原理并不是必须的。

大多数的序列化框架定义了一个内部数据模型,该模型由基本类型(例如原语、字符串和字节数组)组成。这就将序列化的工作可分为两个阶段:前端和后端。前端采用某种类型,并将其分解为数据模型的可序列化类型,然后后端获取数据模型类型,并使用JSON、Bincode、TOML等数据格式写入它们。这就允许在类型的序列化和写入类型的数据格式之间进行清晰的分离。

传统的序列化的一个主要缺点就是:从序列化的值读取、解析和重构类型需要花费相当多的时间。

例如:在JSON中,字符串通过双引号包裹内容并转义其中的无效字符来编码。数字可能也被转换为字符,甚至大多数情况下可能隐式的字段名也被转换为字符串。

所有的这些角色不仅占据空间,也占据了时间。每次我们读取和解析JSON时,都在挑选这些字符,以便找出值是什么,并在内存中重现,f32类型只有4个字节的内存,但是它是用9个字节编码的,我们仍然需要把这9个字符转换成正确的f32。

这种反序列化操作起来很快,但是在游戏和媒体编辑等数据密集型应用程序中,它可能就会存在累积加载时间。

rkyv 通过一种称为零拷贝反序列化的序列化技术提供了一种解决方案。

二、零拷贝反序列化(Zero-Copy Deserialization)

2.1、零拷贝反序列化(Zero-Copy Deserialization)

零拷贝反序列化是一种通过直接引用序列化形式的字节来减少访问和使用数据所需的时间和内存的技术。

这利用了我们必须在内存中加载一些数据以便对其进行反序列化的优势。

{ "quote": "I don't know, I didn't listen." }

例如我们有上述JSON,我们不是将字符拷贝到字符串中,我们可以从JSON缓冲区中借用它作为&str。 &str 的生命周期将取决于缓冲区,并且我们删除了正在使用的字符串之前,不允许删除它。

2.2、部分零拷贝(Partial Zero-Copy)

Serde 和其他工具支持部分零拷贝反序列化,其中反序列化数据的一小部分从序列化形式中借用。例如,字符串可以直接从编码(bincode)的序列化形式只能够借用字节,而不执行任何字符转义。但是,仍然必须创建一个字符串对象来保存反序列化的长度并指向借来的字符。

考虑这个问题的好方法是,即使我们从缓冲区中借用了大量数据,我们仍然需要解析结构。

struct Example<'a> {quote: &'a str,a: &'a [u8; 12],b: u64,c: char,
}

所以缓冲区可能会想这样

I don't know, I didn't listen.AAAAAAAAAAAABBBBBBBBCCCC
^-----------------------------^-----------^-------^---quote: str                    a: [u8; 12] b: u64  c: char
Example {quote: str::from_utf8(&buffer[0..30]).unwrap(),a: &buffer[30..42],b: u64::from_le_bytes(&buffer[42..50]),c: char::from_u32(u32::from_le_bytes(&buffer[50..54]))).unwrap(),
}

我们不能借用像 u64 或 char这样有对齐要求的类型,因为我们的缓冲区可能没有正确对齐。我们必须立即解析并存储它们!尽管我们借用了缓冲区的42字节,但我们错过了最后的12个字节,并且仍然必须解析缓冲区以找出所有内容的位置。

部分零拷贝反序列化可以显著改善内存的使用,并且通常会加快某些反序列化的速度,但是我们需要做一些工作,我们可以走得更远。

2.3、完全零拷贝(Total Zero-Copy)

rkyv 实现了完全零拷贝反序列化,这保证了在反序列化过程中不复制数据,也不做反序列化数据的工作,它通过结构化其编码来实现这一点,使其与源类型的内存表示相同

struct Example {quote: String,a: [u8; 12],b: u64,c: char,
}

缓冲区可能像这样

I don't know, I didn't listen.__QOFFQLENAAAAAAAAAAAABBBBBBBBCCCC
^-----------------------------  ^---^---^-----------^-------^---quote bytes                    pointer  a           b       cand len^-------------------------------Example

在这种情况下,字节被填充到正确的对齐方式,并且 Example 的字段布局与它们所在的内存布局完全相同,反序列化代码可以简单很多。

unsafe { &*buffer.as_ptr().add(32).cast() }

这个操作几乎是零工作量,更重要的是,它不会随我们的数据扩展,不管我们有多少数据,访问数据的方法总是指针偏移和强制类型转换。

这样就开启了极快的数据加载,并使得数据访问速度比传统序列化快几个数量级。

三、体系结构

rkyv的核心是围绕相对指针和三个核心特征构建的:Archive, Serialize, 和 Deserialize。这些特征都有一个相应的变体,支持未知大小的类型:ArchiveUnsized, SerializeUnsized, 和 DeserializeUnsized.

已知大小的类型是构建未知大小类型的基础,rkyv是精确构建的,以便你可以安全和可组合的方式从低级机器中构建更复杂的抽象。

rkyv_dyn 库增加了对trait 对象的支持,它引入了新的trait,并定义了它们如何构建,从而允许对trait 对象进行序列化和反序列化。

3.1、相对指针(Relative pointers)

相对指针是完全零拷贝反序列化的基础,它完全取代了普通指针的使用。考虑磁盘上的零拷贝数据,在使用它之前,我们需要将它加载到内存中,但是我们无法控制它在内存中的加载位置,每次我们加载它,它都可能位于不同的地址,因此它里面的对象将位于不同的地址。

其中一个主要的原因是安全性,每次运行程序时,它都可能在内存中完全不同的随机位置运行,这被称为地址空间布局随机化,它有助于防止利用内存损坏漏洞。

我们最多只能控制零拷数据的对齐,我们需要在这些约束下工作。

这就意味着,我们不能在数据内部或外部存储指向该数据的任何指针,当我们重新加载数据时,它可能不在同一个地址,这将使指针垂悬,并且几乎肯定会导致内存访问冲突,其他一些库(abomonation)存储一些额外的数据,并执行代替反序列化的快速修复步骤。

为了执行修复步骤,abomonation 要求缓冲区具有可变的支持,对于许多用例来说,这是可以的,但有些情况下,我们将无法改变我们的缓冲区,例如我们使用内存映射文件。

普通指针在内存中保存绝对地址,而相对指针保存地址的偏移量,而这将改变指针在移动时的行为

指针自身可以移动自身和目标可以移动
普通指针目标仍然是一个地址目标不在是一个地址
相对指针相对距离改变自己和目标相对距离不便

这正是我们构建完全零拷贝反序列化的数据结构所需要的属性,通过使用相对指针,我们在内存中的任意位置加载数据,并且其中仍然有有效的指针。相对指针也不需要对内存进行写访问,因此我们对整个文件进行内存映射,并以结构化的方式立即访问它们的数据。

具体实现,我们可以查看 RelPtr

3.2、存档(Archive)

实现了 Archive 的类型具有支持零拷贝反序列化的替代表示,分为下面两个步骤

  1. 序列化:该类型的任何依赖项都被序列化,对于字符串,它将是字符串的字符,对于 box 将是 box 的值,对于向量,它将是包含的任何元素。此步骤的任何记录都将保定 Resolver 类型中,并保留以供以后使用,这就是序列化的步骤
  2. 解析步骤:解析器和原始值用于构造输出缓冲区中的存档值,对于字符串,解析器将是字符的位置,对于 box,解析将是已经装箱值的位置,对于向量,解析器嫁给你存元素的位置,将原始值和解析起结合起来,就可以构造存档版本了。
let value = ("hello".to_string(), "world".to_string());

上述的元组规定需要两个字符串紧挨着

0x0000      AA AA AA AA BB BB BB BB
0x0008      CC CC CC CC DD DD DD DD

A 和 B 可能是元组第一个字符串的长度和指针,C 和 D 可能是第二个字符串的长度和指针。

在归档时,我们可能回你先序列化并解析第一个字符串,然后再序列化解析第二个字符串,但是这可能会将第二个字符串的字节方在这两个字符串之间。相反,我们需要为这两个字符串写出字节,然后完成它们的归档,元组不知道字符串需要什么信息来完成字节的归档,所以它们必须通过它们的鸡诶稀奇将它提供给元组。

这样元组就可以

  • 存档第一个字符串(保存解析器)
  • 存档第二个字符串(保存解析器)
  • 用解析器解析第一个字符串
  • 用解析器解析第二个字符串

我们可以保证两个字符串想我们需要的那样紧挨着放在一起。

3.3、序列化(Serialize)

Serialize 为某个对象创建解析器,然后 Archive 将值和该解析器转换为 Archive 类型,拥有一个单独的 Serialize 特征是必要的,因为尽管一个类型可能只有一个存档表示,但是为了创建一个类型,你可以选择满足那些要求。

Serialize 特征在序列化器上进行参数化,Serializer 是一个可变对象,它可以帮助类型序列化自身,像u32和char 这样的最基本类型没有绑定它们的序列化器类型,因为它们可以用任何类型的序列化器序列化自己。而更复杂的类型则需要字节实现 Serializer 的序列化器,Rc和Vec 需要另外实现 SharedSerializeRegistry 和 ScratchSpace。

与 Serialize 不同,Archive 不会对用于生成它的序列化器进行参数化,解析器是用什么序列化器创建的并不中歌谣,更重要的是它是正确创建的。

rkyv 提供了序列化器,提供了序列化标准库类型所需的所有功能,以及其他序列化器组合成所具有组件功能的单个对象的序列化球。

所提供的序列化器提供了广泛的策略和功能,单大多数用例最适合 AllocSerializer。

许多类型需要临时空间来序列化,这是一些额外分配的空间,他们可以临时使用,并在完成后返回,例如 Vec 可能会请求临时空间来存储其元素的解析器,直刀能够系列化所有元素为止。

从序列化器请求临时空间允许多次重复临时空间,这减少在序列化时执行的缓冲内存分配的数量。

3.4、反序列化(Deserialize)

与序列化类似,Deserialize 将参数化病接受反序列化器,并将类型从其存档形式转换回原始形式。与序列化不同的是反序列化在单个步骤中发生,并且没有对应的解析器。

反序列化还对要反序列化到的类型进行参数化,这将允许根据请求将相同的归档类型反序列化为多个不同的非归档类型,这有助于实现多个非常强大的抽象,但可能需要您在反序列化的时候注释类型。

这或多或少提供了一种传统的反序列化,并通过具有非常兼容的表示在一定程度上加快了速度,她还会导致传统反序列化的内容和性能损失,因此在使用它之前,请确保她是你所需要的。自己要可以通过归档版本访问归档数据,就不需要反序列化。

即使是性能最高的序列化框架也会因为需要执行的内存分配量而达到反序列化速度限制。

反序列化的一个很好的用途就是反序列化归档的部分。您可以轻松地遍历归档数据以定位某个子对象,然后只对该部分进行反序列化,而不是整个规定进行反序列化,这种粒度方法提供是零拷贝反序列化和传统反序列化的区别。

反序列化器与序列化器一样,在反序列化期间为对象提供功能。大多数类型不绑定它们的反序列化器,但有些类型(如Rc)需要特殊的反序列化器才能正确地反序列化内存。

3.5、对齐(Alignment)

类型的对齐限制了它在内存中的位置,优化硬件负载和存储。因为rkyv创建对位于序列化字节中的值的引用,所以它确保哦它创建的引用对象类型进行正确对齐。

为了对数据执行算术和逻辑操作,现代cpu 需要将内存中的数据加载到寄存器中,但是 CPU 访问数据的方式通常有硬件限制:它只能访问从字边界开始的数据。 这些字就是 CPU 工作的自然大小,32位机器的字长为4字节,64位机器的字长为8字节。

四、rkyv 使用

use rkyv::{Archive, Deserialize, Serialize};
use rkyv::ser::{Serializer, serializers::AllocSerializer};#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
// This will generate a PartialEq impl between our unarchived and archived types
#[archive(compare(PartialEq))]
// We can pass attributes through to generated types with archive_attr
#[archive_attr(derive(Debug))]
struct Test {int: u8,string: String,option: Option<Vec<i32>>,
}fn main(){let value = Test {int: 42,string: "hello world".to_string(),option: Some(vec![1, 2, 3, 4]),};let mut serializer = AllocSerializer::<0>::default();serializer.serialize_value(&value).unwrap();let bytes = serializer.into_serializer().into_inner();// You can use the safe API with the validation feature turned on,// or you can use the unsafe API (shown here) for maximum performancelet archived = unsafe { rkyv::archived_root::<Test>(&bytes[..]) };assert_eq!(archived, &value);println!("{:#?}", archived);// And you can always deserialize back to the original typelet deserialized: Test = archived.deserialize(&mut rkyv::Infallible).unwrap();assert_eq!(deserialized, value);
}

总结

本章节讲解了零拷贝反序列化的原理和体系结构,以及rkyv的使用

相关文章:

【跟小嘉学 Rust 编程】二十九、Rust 中的零拷贝序列化解决方案(rkyv)

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...

路由器端口转发

什么是路由器端口转发 路由器端口转发是一种网络配置技术&#xff0c;用于将公共网络&#xff08;如互联网&#xff09;上的请求转发到私有网络中的特定设备或服务。它允许外部设备通过路由器访问内部网络中的设备或服务&#xff0c;实现网络上的通信和互动。 路由器端口转发…...

Redis模块一:缓存简介

目录 缓存的定义 应用 生活案例 程序中的缓存 缓存优点 缓存的定义 缓存是⼀个高速数据交换的存储器&#xff0c;使用它可以快速的访问和操作数据。 应用 1.CPU缓存&#xff1a;CPU缓存是位于CPU和内存之间的临时存储器&#xff0c;它的容量通常远小于内存&#xff0…...

【去除若依首页】有些小项目不需要首页,去除方法

第一步 // // // // // // // // // // // // // // // // // // 修改登录页 Login.vue 中 大概144行 &#xff0c;注释掉原有跳转。替换为自己的跳转路径 // // // // // // // // // // // // // this.$router.push({ path: this.redirect || …...

Ardupilot — EKF3使用光流室内定位代码梳理

文章目录 前言 1 Copter.cpp 1.1 void IRAM_ATTR Copter::fast_loop() 1.2 void Copter::read_AHRS(void) 1.3 对象ahrs说明 2 AP_AHRS_NavEKF.cpp 2.1 void AP_AHRS_NavEKF::update(bool skip_ins_update) 2.2 void AP_AHRS_NavEKF::update_EKF3(void) 2.3 对象EKF3说…...

【Linux】自动化构建工具 —— make/makefileLinux第一个小程序 - 进度条

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;Linux编译…...

tensorflow的unet模型

import tensorflow as tf from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Dropout, UpSampling2D, concatenate# 定义 U-Net 模型 def unet(input_size(256, 256, 3)):inputs Input(input_size)# 编码器部分conv1 Conv2D(64, 3, activationrelu, padding…...

(2023 最新版)IntelliJ IDEA 下载安装及配置教程

IntelliJ IDEA下载安装教程&#xff08;图解&#xff09; IntelliJ IDEA 简称 IDEA&#xff0c;由 JetBrains 公司开发&#xff0c;是 Java 编程语言开发的集成环境&#xff0c;具有美观&#xff0c;高效等众多特点。在智能代码助手、代码自动提示、重构、J2EE 支持、各类版本…...

react 实现拖动元素

demo使用create-react-app脚手架创建 删除一些文件&#xff0c;创建一些文件后 结构目录如下截图com/index import Movable from ./move import { useMove } from ./move.hook import * as Operations from ./move.opMovable.useMove useMove Movable.Operations Operationse…...

【EI会议】第二届声学,流体力学与工程国际学术会议(AFME 2023)

第二届声学&#xff0c;流体力学与工程国际学术会议 2023 2nd International Conference on Acoustics, Fluid Mechanics and Engineering&#xff08;AFME 2023&#xff09; 声学、流体力学两个古老的学科发展至今&#xff0c;无时无刻都在影响着我们的生活。小到日常使用的耳…...

Android StringFog 字符串自动加密

一、StringFog 作用 一款自动对dex/aar/jar文件中的字符串进行加密Android插件工具&#xff0c;正如名字所言&#xff0c;给字符串加上一层雾霭&#xff0c;使人难以窥视其真面目。可以用于增加反编译难度&#xff0c;防止字符串代码重复。 支持java/kotlin。支持app打包生成…...

上四休三,未来的期许

近日“少上一天班&#xff0c;究竟香不香”引发关注&#xff0c;英国媒体2月21日报道&#xff0c;一项全世界目前为止参加人数最多的“四天工作制”试验&#xff0c;不久前在英国取得了成功。很多人表示上过四天班之后&#xff0c;给多少钱也回不去五天班的时代了。 来百度APP畅…...

怎么防止360安全卫士修改默认浏览器?

默认的浏览器 原先选项是360极速浏览器&#xff08;如果有安装的话&#xff09;&#xff0c;我这里改成了Chrome。 先解锁 才能修改。...

调整参数提高mysql读写速度

要提升MySQL的写入速度,您可以采取一些参数调整和优化措施,这些措施可以根据您的具体应用和环境进行调整。以下是一些常见的参数和优化建议: InnoDB存储引擎: 如果您使用的是InnoDB存储引擎,确保以下参数被设置得合理: innodb_buffer_pool_size:增加内存池大小,以便更多…...

第一届电子纸产业创新应用论坛-邀请函

...

Go expvar包

介绍与使用 expvar 是 exposed variable的简写 expvar包[1]是 Golang 官方为暴露Go应用内部指标数据所提供的标准对外接口&#xff0c;可以辅助获取和调试全局变量。 其通过init函数将内置的expvarHandler(一个标准http HandlerFunc)注册到http包ListenAndServe创建的默认Serve…...

Yolo v8代码逐行解读

train.py文件 1.FILE Path(__file__).resolve() __file__代表的是train.py文件&#xff0c;Path(__file__).resolve()结果是train.py文件的绝对路径。 2.ROOT FILE.parents[0] 获得train.py父目录的绝对路径 3.sys.path 是一个列表list&#xff0c;里面包含了已经添加到系…...

9.18号作业

完善登录框 点击登录按钮后&#xff0c;判断账号&#xff08;admin&#xff09;和密码&#xff08;123456&#xff09;是否一致&#xff0c;如果匹配失败&#xff0c;则弹出错误对话框&#xff0c;文本内容“账号密码不匹配&#xff0c;是否重新登录”&#xff0c;给定两个按钮…...

Spring源码阅读(spring-framework-5.2.24)

spring-aop spring-aspects spring-beans spring-context 等等 第一步&#xff1a; Tags spring-projects/spring-framework GitHub 找到相应的release版本 第二步&#xff1a; 下载相应版本的gardle&#xff0c;如何看版本 spring-framework/gradle/wrapper /gradl…...

【SpringMVC】文件上传与下载、JREBEL使用

目录 一、引言 二、文件的上传 1、单文件上传 1.1、数据表准备 1.2、添加依赖 1.3、配置文件 1.4、编写表单 1.5、编写controller层 2、多文件上传 2.1、编写form表单 2.2、编写controller层 2.3、测试 三、文件下载 四、JREBEL使用 1、下载注册 2、离线设置 一…...

数据结构 第二章作业 线性表 西安石油大学

在顺序表中插入和删除一个结点需平均移动多少个结点&#xff1f;具体的移动次数取决于 哪两个因素&#xff1f; 在顺序表中插入和删除一个结点时&#xff0c;平均移动的结点数量取决于两个因素&#xff1a;插入/删除位置和当前顺序表的长度。 插入/删除位置&#xff1a;如果要…...

vue.mixin全局混合选项

在Vue.js中&#xff0c;Vue.mixin 是一个用来全局混合(mixin)选项的方法。它允许你在多个组件中共享相同的选项&#xff0c;例如数据、方法、生命周期钩子等。这可以用来在组件之间重复使用一些逻辑或共享一些通用的功能 Vue.mixin({// 在这里定义混合的选项data() {return {s…...

VMware Fusion 13+Ubuntu ARM Server 22.04.3在M2芯片的Mac上共享文件夹

因为Server版没有桌面&#xff0c;VMware Tools不能直接装&#xff0c;导致没办法共享文件。 Ubuntu中的包如果需要更新&#xff0c;先执行下面的步骤 sudo apt update 再执行 sudo apt upgrade 不需要更新的话&#xff0c;直接执行下面的步骤 先把open-vm-tools卸载了 …...

PostgreSQL serial类型

serial类型和序列 postgresql序列号&#xff08;SERIAL&#xff09;类型包括 smallserial&#xff08;smallint,short&#xff09;,serial(int)bigserial(bigint,long long int) 不管是smallserial,serial还是bigserial&#xff0c;其范围都是(1,9223372036854775807)&#…...

[创业之路-76] - 创业公司如何在长期坚持中顺势而为?诚迈科技参观交流有感

目录 一、创业环境 1.1. VUCA乌卡时代&#xff1a;易变、复杂、不确定性、模糊的时代 1.2. 中国用了四十年的时间完成了三次工业革命&#xff1a;机械化、电气化、数字化 1.3. 中国正在经历着第四次工业革命&#xff1a;智能化、生态化、拟人化 1.4 国产替代&#xff1a;国…...

人脸修复祛马赛克算法CodeFormer——C++与Python模型部署

一、人脸修复算法 1.算法简介 CodeFormer是一种基于AI技术深度学习的人脸复原模型&#xff0c;由南洋理工大学和商汤科技联合研究中心联合开发&#xff0c;它能够接收模糊或马赛克图像作为输入&#xff0c;并生成更清晰的原始图像。算法源码地址&#xff1a;https://github.c…...

linux入门到精通-第三章-vi(vim)编辑器

目录 文本编辑器gedit介绍vi(vim)命令模式命令模式编辑模式末行模式 帮助教程保存文件切换到编辑模式光标移动(命令模式下)复制粘贴删除撤销恢复保存退出查找替换可视模式替换模式分屏其他用法配置文件 文本编辑器 gedit介绍 gedit是一个GNOME桌面环境下兼容UTF-8的文本编辑器…...

Mybatis面试题(三)

文章目录 前言一、Xml 映射文件中&#xff0c;除了常见的 select|insert|updae|delete 标签之外&#xff0c;还有哪些标签&#xff1f;二、当实体类中的属性名和表中的字段名不一样&#xff0c;如果将查询的结果封装到指定 pojo&#xff1f;三、模糊查询 like 语句该怎么写四、…...

Qt扩展-KDDockWidgets 简介及配置

Qt扩展-KDDockWidgets 简介及配置] 一、概述二、编译 KDDockWidgets 库1. Cmake Gui 中选择源文件和编译后的路径2. 点击Config&#xff0c;配置好编译器3. 点击Generate4. 在存放编译的文件夹输入如下命令开始编译 三、qmake 配置 一、概述 kdockwidgets是一个由KDAB组织编写…...

Vue3搭配Element Plus 实现候选搜索框效果

直接上代码 <el-col :span"14" class"ipt-col"><el-input v-model"projectName" class"w-50 m-2" input"inputChange" focus"inputFocusFn" blur"inputBlurFn" placeholder"请输入项目名…...

江门网站制作/2019网站seo

之前用过一些编辑器如SublimeText&#xff0c;IDE如phpstorm&#xff0c;IDEA等&#xff1b;这些工具给我的感觉就是&#xff0c;除了给予这些工具应有的功能外&#xff0c;给予开发者更友好&#xff0c;更舒服的界面。Eclipse很早就开始使用了&#xff0c;之前在使用时&#x…...

家居企业网站建设如何/百度区域代理

刚看完urlretrieve函数&#xff0c;想要实战一下它的效果&#xff0c;于是找了国家地理杂志中国官网爬一下&#xff0c;网站http://www.nationalgeographic.com.cn/ 开发环境是Python2.7&&Pycharm 图片的src是这样的&#xff1a; 我们用正则&&BeautifulSoup匹配…...

广州外贸网站建设公司/哈尔滨百度公司地址

什么是面向对象OO&#xff1a;可以先看下 https://www.jianshu.com/p/224d8fc4d0f0 提起面向对象&#xff0c;肯定都会先想到三大特性&#xff1a;封装&#xff0c;继承&#xff0c;多态。那这三大特性具体怎么理解呢&#xff1f;可以先在脑子里过一下。 如题&#xff0c;举个栗…...

怎样临沂网站建设/找资源

在很多集群架构中&#xff0c;为了保证集群数据的一致性&#xff0c;都会使用一致性哈希算法&#xff0c;因为一致性哈希算法&#xff0c;可以保证无论是增加节点&#xff0c;还是减少节点&#xff0c;被影响的数据都是一小部分数据。不过&#xff0c;Redis集群例外&#xff0c…...

南昌网站建设讯息/2021百度热搜年度榜

为了评估模型拟合的好坏&#xff0c;通常用损失函数&#xff08;觉得严格来说相当于下面的目标函数&#xff09;来度量拟合的程度。损失函数极小化&#xff0c;意味着拟合程度最好&#xff0c;对应的模型参数即为最优参数。 每一个算法都有一个目标函数&#xff08;objective f…...

网站优化的意义/好用的种子搜索引擎

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2022茶艺师&#xff08;中级&#xff09;考试练习题为茶艺师&#xff08;中级&#xff09;考题考前必练习题目&#xff01;2022年茶艺师&#xff08;中级&#xff09;考试模拟100题模拟考试平台操作依据茶艺师&#x…...