MySQL进阶:InnoDB引擎(逻辑存储结构、架构、事务原理、MVCC(面试高频))

news2024/11/15 23:39:12

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:MySQL进阶:全局锁、表级锁、行级锁总结
📚订阅专栏:MySQL进阶
希望文章对你们有所帮助

MVCC很重要,是大厂面试的高频面试题,学起来也不是很容易,需要瞻前顾后,总之要多总结多思考。
理解MVCC可以帮助你更好的理解事务的性质,大家都知道RC隔离级别的事务会出现不可重复读问题,但是RR隔离级别的事务却解决了不可重复读问题,解决的方法就是通过MVCC。
希望这篇文章能让你醍醐灌顶,不惧面试!

文章目录

  • 逻辑存储结构
  • 架构
    • 概述
    • 内存结构
    • 磁盘结构
    • 后台线程
  • 事务原理
    • 事务基础
    • redo log
    • undo log
  • MVCC(高频面试)
    • 基本概念
    • 隐藏字段
      • 介绍
    • undo log版本链
      • 介绍
      • 版本链(核心重点)
    • ReadView
    • ReadView原理剖析(重难点)
      • RC隔离级别
      • RR隔离级别

逻辑存储结构

InnoDB的逻辑存储结构如下所示:
在这里插入图片描述
1、表空间

表空间是InnoDB存储引擎逻辑结构的最高层, 如果用户启用了参数 innodb_file_per_table(在8.0版本中默认开启) ,则每张表都会有一个表空间(xxx.ibd),一个mysql实例可以对应多个表空间,用于存储记录、索引等数据。

2、段

段,分为数据段(Leaf node segment)、索引段(Non-leaf node segment)、回滚段(Rollback segment),InnoDB是索引组织表,数据段就是B+树的叶子节点,索引段即为B+树的非叶子节点。段用来管理多个Extent(区)。

3、区

区,表空间的单元结构,每个区的大小为1M。 默认情况下,InnoDB存储引擎页大小为16K, 即一个区中一共有64个连续的页。

4、页

页,是InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。为了保证页的连续性InnoDB存储引擎每次从磁盘申请 4-5 个区。

5、行

InnoDB 存储引擎数据是按行进行存放的
在行中,默认有2个隐藏字段:

  • Trx_id:每次对某条记录进行改动时,都会把对应的事务id赋值给trx_id隐藏列(相当于存储了最后一条记录的事务id)
  • Roll_pointer:每次对某条引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。

架构

概述

MySQL5.5开始,默认使用InnoDB存储引擎,它擅长事务处理,具有崩溃恢复特性,在日常开发中使用非常广泛。下面是InnoDB架构图,左侧为内存结构,右侧为磁盘结构。
在这里插入图片描述

内存结构

在这里插入图片描述
主要分四大块:
1、Buffer Pool

InnoDB存储引擎基于磁盘文件存储,访问物理硬盘和在内存中进行访问,速度相差很大,为了尽可能弥补这两者之间的I/O效率的差值,就需要把经常使用的数据加载到缓冲池中,避免每次访问都进行磁盘I/O。
缓冲池 Buffer Pool,是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。
可以看到缓存池是以Page(页)为单位的,底层采用链表数据结构来管理Page。根据状态将Page分为三种类型:

  • free page:空闲page,未被使用。
  • clean page:被使用page,数据没有被修改过。
  • dirty page:脏页,被使用page,数据被修改过,还没有刷到磁盘上,导致数据与磁盘的数据产生了不一致

2、Change Buffer

Change Buffer,更改缓冲区(针对于非唯一二级索引页),在执行DML语句时,如果这些数据Page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区 Change Buffer中,在未来数据被读取时,再将数据合并恢复到Buffer Pool中,再将合并后的数据刷新到磁盘中。

我们可以思考一下Change Buffer存在的意义。首先对于一个非唯一的二级索引页(那就肯定不会是唯一索引或者主键索引了),可能会存在两个字段值是一样的,但是它们肯定的主键id肯定不一致:
在这里插入图片描述
与聚集索引相比较,聚集索引的主键id都是顺序插入的,但是二级索引的叶子结点挂载的主键id并不是顺序的,相对更随机。
那么,删除和更新操作可能操作了多条数据,而在二级索引树中,他们的位置又不是相邻的,这样就会浪费了更多的磁盘IO。
因此,有了ChangeBuffer之后,我们可以在缓冲池中进行合并处理,减少磁盘IO。

3、Adaptive Hash Index

自适应hash索引,用于优化对Buffer Pool数据的查询。MySQL的innoDB引擎中虽然没有直接支持hash索引,但是给我们提供了一个功能就是这个自适应hash索引。因为前面我们讲到过,hash索引在进行等值匹配时,一般性能是要高于B+树的,因为hash索引一般只需要一次IO即可,而B+树,可能需要几次匹配,所以hash索引的效率要高,但是hash索引又不适合做范围查询、模糊匹配等。
InnoDB存储引擎会监控对表上各索引页的查询,如果观察到在特定的条件下hash索引可以提升速度,则建立hash索引,称之为自适应hash索引。
注意:自适应哈希索引,无需人工干预,是系统根据情况自动完成

4、Log Buffer

Log Buffer:日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log 、undo log)。默认大小为 16MB,日志缓冲区的日志会定期刷新到磁盘中。如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘 I/O。

磁盘结构

在这里插入图片描述
1、System Tablespace

系统表空间是更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。

2、File-Per-Table Tablespaces

如果开启了innodb_file_per_table开关 ,则每个表的文件表空间包含单个InnoDB表的数据和索引 ,并存储在文件系统上的单个数据文件中。(默认开启)

3、General Tablespaces
通用表空间,需要通过 CREATE TABLESPACE 语法创建通用表空间,在创建表时,可以指定该表空间。
创建表空间:

CREATE TABLESPACE ts_name ADD DATAFILE 'file_name' ENGINE = engine_name;

创建表时指定表空间:

CREATE TABLE xxx ... TABLESPACE ts_name;

4、Undo Tablespaces

撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16M),用于存储undo log日志。

5、Temporary Tablespaces

InnoDB使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。

6、Doublewrite Buffer Files

双写缓冲区,innoDB引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据。

7、Redo Log

重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo logbuffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中, 用于在刷新脏页到磁盘时,发生错误时, 进行数据恢复使用。

后台线程

内存中我们所更新的数据要到磁盘当中,需要涉及到一组后台线程。
在这里插入图片描述
1、Master Thread

核心后台线程,负责调度其他线程,还负责将缓冲池中的数据异步刷新到磁盘中, 保持数据的一致性。还包括脏页的刷新、合并插入缓存、undo页的回收。

2、IO Thread

在InnoDB存储引擎中大量使用了AIO来处理IO请求, 这样可以极大地提高数据库的性能,而IOThread主要负责这些IO请求的回调。

线程类型默认个数职责
Read thread4负责读操作
Write thread4负责写操作
Log thread1负责将日志缓冲区刷新到磁盘
Insert buffer thread1负责将写缓冲器内容刷新到磁盘

3、Purge Thread

主要用于回收事务已经提交了的undo log,在事务提交之后,undo log可能不用了,就用它来回收

4、Page Cleaner Thread

协助 Master Thread 刷新脏页到磁盘的线程,它可以减轻 Master Thread 的工作压力,减少阻塞

事务原理

事务基础

MySQL事务相关的知识是很常考的,包括事务的四大特性,这一部分内容可以看我之前的文章:
MySQL进阶:MySQL事务、并发事务问题及隔离级别
简单总结一下,事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
四大特性:

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

要研究事务的原理,实际上就是研究MySQL的InnoDB引擎是如何保证事务的四大特性的。
对于这都四大特性,实际上分给2个部分:

1、原子性、一致性、持久性:由InnoDB的2份日志保证的,一份是redo log,一份是undo log
2、隔离性:通过数据库的锁以及MVCC来保证的

对于锁机制实现的隔离性,可以看之前的文章:
MySQL进阶:全局锁、表级锁、行级锁总结

这里主要就是来研究一下redolog,undolog以及MVCC。

redo log

重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。
该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo logfile),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中, 用于在刷新脏页到磁盘,发生错误时, 进行数据恢复使用。

若没有redo log:

1、当我们在一个事务中,执行多个增删改的操作时,InnoDB引擎会先操作缓冲池中的数据,如果缓冲区没有对应的数据,会通过后台线程将磁盘中的数据加载出来,存放在缓冲区中,然后将缓冲池中的数据修改,修改后的数据页我们称为脏页。
2、脏页在一定的时机要通过后台线程刷新到磁盘中,从而保证缓冲区与磁盘的数据一致。
3、由于缓冲区的脏页数据并不是实时刷新的,而是一段时间之后将缓冲区的数据刷新到磁盘中,假如刷新到磁盘的过程出错了,而提示给用户事务提交成功,而数据却没有持久化下来,这就出现问题了,没有保证事务的持久性。

若有redo log:

当对缓冲区的数据进行增删改之后,会首先将操作的数据页的变化,记录在redo log buffer中。在事务提交时,会将redo log buffer中的数据刷新到redo log磁盘文件中。
过一段时间之后,如果刷新缓冲区的脏页到磁盘时,发生错误,此时就可以借助于redo log进行数据恢复,这样就保证了事务的持久性。
如果脏页成功刷新到磁盘或者涉及到的数据已经落盘,此时redolog就没有作用了,就可以删除了,所以存在的两个redolog文件是循环写的。

在这里我们看出内存中的redo log buffer和磁盘中的redo log是如何工作的,那么为何每次提交事务的时候,redo log buffer要刷新到磁盘中的redo log中,而不是直接刷新到磁盘中呢?

因为在业务操作中,我们操作数据一般都是随机读写磁盘的,而不是顺序读写磁盘。
而redo log是日志文件,都是顺序写的,顺序写的效率要远大于随机写,这种先写日志的方式,我们称之为WAL(Write-Ahead Logging)

undo log

回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚(保证事务的原子性)和MVCC(多版本并发控制)。

undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。

  • Undo log销毁:undo log在事务执行时产生,事务提交时,并不会立即删除undo log,因为这些日志可能还用于MVCC。
  • Undo log存储:undo log采用段的方式进行管理和记录,存放在前面介绍的rollback segment回滚段中,内部包含1024个undo log segment

MVCC(高频面试)

基本概念

1、当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select … lock in share mode(共享锁),select … for update、update、insert、delete(排他锁)都是一种当前读。
在这里插入图片描述
可以看到,即便在默认的RR隔离级别下,事务A依然可以读取到事务B最新提交的内容,只是因为查询语句的后面加上了lock in share mode共享锁,此时是当前读操作。
同理,加上排他锁的时候,也是当前当前读操作。

2、快照读
简单的select(不加锁)就是快照读,读取的是记录数据的可见版本,很有可能是历史数据,不加锁,那么读操作不会被阻塞。

  • Read Committed:每次select,都生成一个快照读
  • Repeatable Read(默认):开启事务后第一个select语句才是快照读的地方,后续复用
  • Serializable:快照读会退化为当前读

在这里插入图片描述
可以看到,即便事务B提交了数据,事务A也查不到,就是因为select是快照读,在默认的RR隔离级别下,开启事务后第一个select语句才是快照读的地方,后面执行相同的select语句都是从快照中获取数据,可能不是最新数据(这样当然也保证了可重复读,看不懂很正常,读完后面的原理剖析就会明白)。
3、MVCC
全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。

隐藏字段

介绍

在这里插入图片描述
当我们创建了上面的这张表,我们在查看表结构的时候,就可以显式的看到这三个字段。 实际上除了这三个字段以外,InnoDB还会自动的给我们添加三个隐藏字段及其含义分别是:

隐藏字段含义
DB_TRX_ID最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID(自增)
DB_ROLL_PTR回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本
DB_ROW_ID隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段(非必须)

undo log版本链

介绍

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。
当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。
而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。

版本链(核心重点)

在这里插入图片描述
对于这张表(加了两个隐藏字段),我们设置四个并发事务(2-5,事务1是创建这张表并赋予上述数据,已经commit了)同时操作这张表:

1、第一步
在这里插入图片描述
当事务2执行第一条修改语句时,会记录undo log日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。
在这里插入图片描述
2、第二步
在这里插入图片描述
当事务3执行第一条修改语句时,也会记录undo log日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。
在这里插入图片描述
第三步
在这里插入图片描述
当事务4执行第一条修改语句时,也会记录undo log日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。
在这里插入图片描述

最终我们发现,不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。

那么简单的select语句(快照读)到底是怎么发现历史版本的呢?这需要使用ReadView(读视图)来实现

ReadView

这部分先看概念并自己尝试理解,很可能看不懂,也很正常,硬着头皮看下去自然会醍醐灌顶的。
ReadView(读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务id(就是还没有提交的事务的id)。
ReadView中包含了四个核心字段:

字段含义
m_ids当前活跃的事务ID集合
min_trx_id最小活跃事务ID
max_trx_id预分配事务ID,即当前最大事务的ID+1(事务ID是自增的)
creator_trx_idReadView创建者的事务ID

而在ReadView中就规定了undo log版本链的访问规则:

条件是否可以访问说明
trx_id==creator_trx_id可以访问该版本成立,说明数据是当前这个事务更改的
trx_id<min_trx_id可以访问该版本成立,说明数据已经提交了
trx_id>max_trx_id不可以访问成立,说明该事务是在ReadView生成后开启的
min_trx<=trx_id<=max_trx_id若trx_id不在m_ids中,则可以访问该版本成立,说明数据已经提交

上面的访问规则可以说是有点复杂的,需要剖析一下。

需要注意的是,不同的隔离级别,生成ReadView的时机是不一样的:

  • READ COMMITTED:在事务中每一次执行快照读时生成ReadView
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView

ReadView原理剖析(重难点)

RC隔离级别

RC隔离级别下,在事务中每一次执行快照读时生成ReadView。
在这里,分析下上述例子中的事务5如何进行两次快照读的。

由于隔离级别为Read Committed,所以每一次进行快照读都会生成一个ReadView,那么两次生成的ReadView如下:
在这里插入图片描述
分析第一次快照读:
活跃的事务有3、4、5,显然min_trx_id=3,max_trx_id=6(5+1),当前事务的id为creator_trx_id=5,而此时的记录中的事务id为trx_id=4。
在这里插入图片描述

1、先匹配地址为0x00003这条记录,将4代入匹配规则,可以发现四条规则都不满足
2、匹配第二条,地址为0x00002的这条记录,对应的trx_id=3,代入匹配规则,四条规则都不满足
3、匹配第三条,地址为0x00001的这条记录,对应的trx_id=2,代入匹配规则,发现匹配规则②满足要求,所以,此次快照读的结果就是这条数据
而事实上,此时进行查询的时候,只有事务2是提交了的,因此只能快照读出事务2处理的历史数据。

分析第二次快照读:
在这里插入图片描述

1、先匹配最开始地址为0x00003的这条记录,这条记录对应的trx_id=4,代入匹配规则,都不满足
2、匹配地址为0x00002的这条记录,这条记录对应的trx_id=3,代入匹配规则,满足规则②,那么返回这条记录。
事实上,此次查询前,事务3已经提交了,快照读出来的就是事务3处理过后的数据。

RR隔离级别

RR是可重复读(解决了不可重复读的事务并发问题),也就是说,在一个事务中,执行两次相同的select语句,查询到的结果是一样的。

那么RR隔离级别是如何解决的不可重复读呢?就是因为RR隔离级别下,只在事务中第一次执行快照读时生成ReadView,后续会复用该ReadView:
在这里插入图片描述
那么,容易知道,既然ReadView都一样, ReadView的版本链匹配规则也一样, 那么最终快照读返回的结果也是一样的。

总之,MVCC的实现原理就是通过InnoDB表的隐藏字段、UndoLog 版本链、ReadView来实现的。
而MVCC+锁,则实现了事务的隔离性。而一致性则是由redolog与undolog保证的。

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

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

相关文章

jenkins实战(1)

一, Jenkins官网介绍: Jenkins 持续集成、持续部署 下载地址:Jenkins download and deployment 提供两种类型: LTS(长期版)和Weekly(最近一周的版本) 注: 必须是Java8及以上版本(官网针对这一点有做说明) 二, 安装 下载war包,java -jar XXX --httpPort8081 或 下载war包…

为什么说 TiDB 在线扩容对业务几乎没有影响

本文讨论了分布式数据库在在线扩容方面的挑战&#xff0c; 详细解释了一般分布式数据库和 TiDB 在扩容机制上的不同。 一般分布式数据库在进行在线扩容时&#xff0c;需要重新平衡数据分布&#xff0c;可能会影响系统的可用性和 IO 消耗。 相比之下&#xff0c;TiDB 的存算分离…

五、西瓜书——集成学习

1.个体与集成 集成学习通过将多个学习器进行结合,常可获得比单一学习器显著优越的泛化性能&#xff0c;这对“弱学习器”(weak learner)尤为明显因此集成学习的很多理论研究都是针对弱学习器进行的而基学习器有时也被直接称为弱学习器。 要获得好的集成个体学习器应“好而不同”…

mybatis开发一个分页插件、mybatis实现分页、mybatis拦截器

mybatis开发一个分页插件、mybatis实现分页、mybatis拦截器 通过官网的mybatis插件说明可知&#xff0c;我们可以通过拦截器进行开发一个插件。 例如这样的&#xff1a; UserMapper mapper sqlSession.getMapper(UserMapper.class);// 开始分页MagicPage.startPage(1, 3);//…

八. 实战:CUDA-BEVFusion部署分析-分析BEVFusion中各个ONNX

目录 前言0. 简述1. camera.backbone.onnx(fp16)2. camera.backbone.onnx(int8)3. camera.vtransform.onnx(fp16)4. fuser.onnx(fp16)5. fuser.onnx(int8)6. lidar.backbone.xyz.onnx7. head.bbox.onnx(fp16)总结下载链接参考 前言 自动驾驶之心推出的《CUDA与TensorRT部署实战…

【C++】vector的使用和模拟实现(超级详解!!!!)

文章目录 前言1.vector的介绍及使用1.1 vector的介绍1.2 vector的使用1.2.1 vector的定义1.2.2 vector iterator 的使用1.2.3 vector 空间增长问题1.2.3 vector 增删查改1.2.4 vector 迭代器失效问题。&#xff08;重点!!!!!!&#xff09;1.2.5 vector 在OJ中有关的练习题 2.ve…

蓝桥杯倒计时 41天 - KMP 算法

KMP算法 KMP算法是一种字符串匹配算法&#xff0c;用于匹配模式串P在文本串S中出现的所有位置。 例如S“ababac&#xff0c;P“aba”&#xff0c;那么出现的所有位置是13。 在初学KMP时&#xff0c;我们只需要记住和学会使用模板即可&#xff0c;对其原理只需简单理解&#xff…

WiFi模块引领智能家居革命:连接未来的生活

随着科技的快速发展&#xff0c;智能家居正成为现代生活的一部分&#xff0c;极大地改变了我们与家庭环境互动的方式。其中&#xff0c;WiFi模块作为关键的连接技术&#xff0c;在推动智能家居革命中发挥着不可忽视的作用。本文将深入探讨WiFi模块如何驱动智能家居革命。 设备互…

Maven实战(2)之搭建maven私服

一, 背景: 如果使用国外镜像,下载速度比较慢; 如果使用阿里云镜像,速度还算OK,但是假如网速不好的时候,其实也是比较慢的; 如果没有网的情况下更加下载不了. 二, 本地仓库、个人/公司私服、远程仓库关系如下: 三, 下载安装nexus私服 略

如何在Window系统部署VisualSVN服务并结合cpolar实现无公网ip远程访问

文章目录 前言1. VisualSVN安装与配置2. VisualSVN Server管理界面配置3. 安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4. 固定公网地址访问 前言 SVN 是 subversion 的缩写&#xff0c;是一个开放源代码的版本控制系统…

Mixtral模型解读

Mixtral 8x7B(Mistral MoE) 1.Mistral 7B模型 Mistral 7B模型与Llama2 7B模型结构整体上是相似的&#xff0c;其结构参数如下所示。 细节上来说&#xff0c;他有两点不同。 1.1SWA(Sliding Window Attention) ​ 一般的Attention来说&#xff0c;是Q与KV-Cache做内积&#…

23端口登录的Telnet命令+传输协议FTP命令

一、23端口登录的Telnet命令 Telnet是传输控制协议/互联网协议&#xff08;TCP/IP&#xff09;网络&#xff08;如Internet&#xff09;的登录和仿真程序&#xff0c;主要用于Internet会话。基本功能是允许用户登录进入远程主机程序。 常用的Telnet命令 Telnet命令的格式为&…

基础算法(四)(递归)

1.递归算法的介绍&#xff1a; 概念&#xff1a;递归是指函数直接或间接调用自身的过程。 解释递归的两个关键要素&#xff1a; 基本情况&#xff08;递归终止条件&#xff09;&#xff1a;递归函数中的一个条件&#xff0c;当满足该条件时&#xff0c;递归终止&#xff0c;避…

C++11中的auto、基于范围的for循环、指针空值nullptr

目录 auto关键字 使用原因 历史背景 C11中的auto auto的使用案例 auto 指针/引用 同一行定义多个变量 typeid关键字 基于范围的for循环 范围for的语法 范围for的使用条件 指针空值nullptr C98中的指针空值 C11中的指针空值 auto关键字 使用原因 随着程序越…

Decoupled Knowledge Distillation解耦知识蒸馏

Decoupled Knowledge Distillation解耦知识蒸馏 现有的蒸馏方法主要是基于从中间层提取深层特征&#xff0c;而忽略了Logit蒸馏的重要性。为了给logit蒸馏研究提供一个新的视角&#xff0c;我们将经典的KD损失重新表述为两部分&#xff0c;即目标类知识蒸馏&#xff08;TCKD&a…

JavaSec 基础之五大不安全组件

文章目录 不安全组件(框架)-Shiro&FastJson&Jackson&XStream&Log4jLog4jShiroJacksonFastJsonXStream 不安全组件(框架)-Shiro&FastJson&Jackson&XStream&Log4j Log4j Apache的一个开源项目&#xff0c;是一个基于Java的日志记录框架。 历史…

python学习笔记------元组

元组的定义 定义元组使用小括号&#xff0c;且使用逗号隔开各个数据&#xff0c;数据是不同的数据类型 定义元组字面量&#xff1a;(元素,元素,元素,......,元素) 例如&#xff1a;(1,"hello") 定义元组变量&#xff1a;变量名称(元素,元素,元素,......,元素)…

哈希表是什么?

一、哈希表是什么&#xff1f; 哈希表&#xff0c;也称为散列表&#xff0c;是一种根据关键码值&#xff08;Key value&#xff09;直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录&#xff0c;从而加快查找速度。这个映射函数叫做散列函数&#xff08…

C#与VisionPro联合开发——单例模式

单例模式 单例模式是一种设计模式&#xff0c;用于确保类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。单例模式通常用于需要全局访问一个共享资源或状态的情况&#xff0c;以避免多个实例引入不必要的复杂性或资源浪费。 Form1 的代码展示 using System; usi…

初阶数据结构之---栈和队列(C语言)

引言 在顺序表和链表那篇博客中提到过&#xff0c;栈和队列也属于线性表 线性表&#xff1a; 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构。线性表在逻辑上是线性结构&#xff0c;也就是说是连…