Redis从入门到精通【进阶篇】之对象机制详解

news2024/11/24 18:00:41

文章目录

  • 0. 前言
  • 1. 详解
    • 1.1 redisObject 对象设计目的
    • 1.2 redisObject数据结构
    • 1.2 Redis 是如何使用redisObject
      • 1.2.1. 对象创建
      • 1.2.2. 对象引用计数
      • 1.2.3. 对象共享
      • 1.2.4. 对象的编码方式
      • 1.2.4. 对象的值
  • 2. 总结
    • 2.1. redisObject对象如何实现数据共享和对象池技术?
    • 2.2. redisObject对象的大小是否会随着数据类型的不同而变化
    • 2.3. Redis中的对象池技术如何管理内存?
    • 2.4.Redis中的共享池如何管理共享字符串对象?
    • 2.5. 如何判断一个字符串对象是否在共享池中?
  • 3. Redis从入门到精通系列文章

在这里插入图片描述

0. 前言

Redis 之所以是一款高性能和受大家欢迎的的内存数据库,不仅是它支持多种数据类型,包括字符串、列表、哈希、集合、有序集合等数据结构。而且这些数据类型都是由对象结构(redisObject) 和对应编码的数据结构组合而成。在 Redis 中,对象结构是所有数据类型的底层实现,它包含了数据对象的类型、引用计数、编码方式、值等信息。使得Redis在性能和内存利用方面有着无可比拟的地位。奠定了它的江湖地位。

本文将重点介绍 Redis 对象结构(redisObject) 的实现原理。我们将从对象结构的基本原理入手,分析对象结构的组成部分,以及对象结构的内存管理和引用计数等重要概念。同时,我们也会探讨 Redis 对象结构的应用场景和实际应用案例,帮助大家更好地理解 Redis 的内部实现机制。

今天我们换一种分享方式,先抛出一些问题,这些问题可能是面试经常被问到的

1. 什么是redisObject对象?
2. redisObject数据结构解析?
4. redisObject对象如何实现数据共享和对象池技术?
5. redisObject对象的大小是否会随着数据类型的不同而变化?
6. redisObject对象的序列化和反序列化有哪些常用的方法?
7. Redis中还有哪些技术可以提高系统的性能和稳定性?
8. Redis中的对象池技术如何管理内存?
9. Redis中的共享池如何管理共享字符串对象?

1. 详解

Redis 中的 redisObject 对象是 Redis 中的基本数据结构,它是 Redis 实现高效存储和处理数据的关键之一。redisObject 对象可以表示各种不同类型的数据,如字符串、列表、哈希表等,它们在 Redis 中被广泛使用。

1.1 redisObject 对象设计目的

增强数据结构的灵活性:Redis 中支持多种不同类型的数据结构,如字符串、列表、哈希表、集合和有序集合等,这些数据结构在 Redis 中都被表示为 redisObject 对象。通过将不同类型的数据统一封装成 redisObject 对象,Redis 可以更加灵活地处理不同类型的数据,从而支持多种不同的应用场景。

简化内存管理:Redis 中所有数据都存储在内存中,因此需要对内存进行有效的管理。通过使用 redisObject 对象可以简化内存管理的复杂性,因为 redisObject 对象可以自己管理内部的内存空间,从而避免了手动管理内存的问题。

提高数据存储和访问的效率:Redis 中的 redisObject 对象是一个轻量级的对象,它的大小通常只有几个字节,因此可以快速地存储和访问。此外,Redis 还通过对象共享和对象池等技术来优化内存使用效率,从而提高了数据存储和访问的效率。

方便数据序列化和反序列化:Redis 中的 redisObject 对象可以方便地进行序列化和反序列化,因为 redisObject 对象是一种结构化的数据类型,它可以被序列化成二进制格式或其他格式,方便数据的传输和存储。

1.2 redisObject数据结构

redisObject 是 Redis 中的一个基本数据结构,它用于表示 Redis 中的各种数据类型,如字符串、列表、哈希表、集合和有序集合等。redisObject 结构体定义如下:
源码地址 https://github.com/redis/redis/blob/6.0/src/server.h
在这里插入图片描述
我把源码复制出来解析一下

typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                            * LFU data (least significant 8 bits frequency
                            * and most significant 16 bits access time). */
    int refcount;
    void *ptr;
} robj;

字段含义:

  • type:表示 redisObject 对象的类型,它是一个 4 位的整数,用于区分不同的数据类型。Redis 中支持多种不同的数据类型,如字符串、列表、哈希表、集合和有序集合等,每种数据类型都有一个对应的 type 值。
  • encoding:表示 redisObject 对象的编码方式,它是一个 4 位的整数,用于区分不同的编码方式。由于 Redis 中的每种数据类型可以用多种不同的编码方式来表示,因此需要使用 encoding 字段来区分不同的编码方式。
  • lru:表示 redisObject 对象的 LRU 时间,它是一个整数,用于记录对象最后一次被访问的时间。LRU(Least Recently Used)算法用于判断哪些对象最近最少使用,从而进行淘汰。
  • refcount:表示 redisObject 对象的引用计数,它是一个整数,用于记录当前对象被引用的次数。当引用计数为 0 时,表示当前对象可以被释放。
  • ptr:表示 redisObject 对象的实际数据,它是一个指针,指向对象的实际数据。不同类型的对象的实际数据类型不同,如字符串对象的实际数据是一个 char 数组,列表对象的实际数据是一个链表等。

1.2 Redis 是如何使用redisObject

Redis 在使用 redisObject 时,主要涉及以下几个方面:

1.2.1. 对象创建

Redis 使用 redisObjectCreate 函数来创建数据对象,并初始化对象的类型、编码方式和实际值等属性。在创建对象时,Redis 会根据实际值的类型来选择适当的编码方式,以提高内存使用效率。
redisObjectCreate 函数的定义和实现位于 Redis 源码的 src/object.c 文件中。
源码位置https://github.com/redis/redis/blob/6.0/src/object.c
还是老办法我们把源码复制出来解析一下

robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));
    o->type = type;
    o->encoding = REDIS_ENCODING_RAW;
    o->ptr = ptr;
    o->refcount = 1;
    return o;
}

我们在源码中可以看到,createObject 函数接受两个参数:type 和 ptr,分别表示对象的类型和实际值。在函数内部,它首先使用 zmalloc 函数分配一块内存,大小为 redisObject 结构体的大小。然后,它初始化 redisObject 结构体的成员变量,包括对象类型(type)、编码方式(encoding)、实际值指针(ptr) 和引用计数(refcount)。最后,它返回创建的 redisObject 对象。

声明一下Redis 中还有其他的 redisObjectCreate 函数,用于创建不同类型的数据对象。例如,createStringObject 函数用于创建字符串对象,createListObject 函数用于创建列表对象,createSetObject 函数用于创建集合对象等。这些函数都是在 src/object.c 源码 文件中定义和实现的。
我就不仔细讲了方便大家理解记忆点击上面的链接进去大概扫一遍源码有个基本认知

1.2.2. 对象引用计数

Redis 使用对象引用计数来管理数据对象的生命周期,确保对象在使用过程中不会被意外释放。每个对象都包含一个引用计数(refcount)属性,表示对象当前被引用的次数。在对象被创建时,引用计数初始化为1,当对象被引用时,引用计数加1,当对象被释放时,引用计数减1。当引用计数为0时,对象被释放。所以这个也是JVM 的GC 机制中的一种策略。引用计数法。思想和目的都是一样的,大家可以类比学习。

1.2.3. 对象共享

Redis 中有些数据对象是共享的,例如字符串常量、空列表等。为了节省内存,Redis 使用共享对象来表示这些数据对象,多个变量可以共享同一个对象。Redis 通过将共享对象的引用计数设置为负数来区分共享对象和普通对象。其实如果是java同学看到这块可能会联想到java语言中的一个特性,叫做常量池(Constant Pool)。最常见的字符串常量池(String Pool)专门用于存储字符串常量对象。
Java 中的字符串常量池是一种特殊的内存区域,用于存储字符串常量对象。这些字符串常量对象是在编译期间或运行期间通过字面量(Literal)创建的,例如字符串直接量、字符直接量等。当 Java 程序中出现字符串直接量时,Java 编译器会自动将其添加到字符串常量池中,并在运行时共享这些字符串常量对象,以提高内存使用效率。
那么Redis其实也是这个思想和java的常量池思想类似,以提高内存使用效率 。所以我们可以看到其实设计思想和语言无关,只要在恰当的场景中,能够有效的解决某种问题,就是最优秀的设计思想。其实C++,python,javascript 都使用这种思想,以提高内存使用效率和性能。 所以大家理解和对比记忆很重要,会发现计算机的世界里有的一套思想横行几十年还都是最优解。好了不扯了,咱们继续。

redis预分配的值对象如下:各种命令的返回值,比如成功时返回的OK,错误时返回的ERROR,命令入队事务时返回的QUEUE,等等包括0在内,小于REDIS_SHARED_INTEGERS的所有整数(REDIS_SHARED_INTEGERS的默认值是10000)

Redis预分配的整数对象和字符串值对象的源码位置在Redis的src目录下的以下文件中:

  • redis.h:定义了Redis的整数对象结构体redisObject和字符串值对象结构体robj,以及REDIS_SHARED_INTEGERS宏定义。

  • object.c:定义了Redis的对象操作函数,包括创建、释放、增加和减少引用计数等操作,同时也包括预分配整数对象和字符串值对象的函数initServerSharingObjects()。
    在这里插入图片描述

在initServerSharingObjects()函数中,Redis会预分配一定数量的整数对象和字符串值对象,并将它们缓存在全局共享对象池中。这些对象的数量可以通过在redis.conf配置文件中设置sharedobjects-pool-size选项来调整。默认情况下,REDIS_SHARED_INTEGERS宏定义的值为10000,表示预分配10000个整数对象,而字符串值对象则根据需要预分配一些常见的字符串值对象,如"OK"、"ERROR"和"QUEUE"等。

1.2.4. 对象的编码方式

Redis 支持多种编码方式来表示不同类型的数据对象,例如字符串可以使用 int、embstr 或 raw 编码方式。Redis 会根据实际值的类型和大小来选择适当的编码方式,以提高内存使用效率。在对象创建时,Redis 会自动选择适当的编码方式,并将编码方式保存在对象的编码(encoding)属性中。
对象的 ptr 指针指向对象的底层实现数据结构, 而这些数据结构由对象的 encoding 属性决定。encoding 属性记录了对象所使用的编码, 也即是说这个对象使用了什么数据结构作为对象的底层实现。

/* Objects encoding. Some kind of objects like Strings and Hashes can be
 * internally represented in multiple ways. The 'encoding' field of the object
 * is set to one of this fields for this object. */
// encoding 的10种类型
#define OBJ_ENCODING_RAW 0     /* Raw representation */     //原始表示方式,字符串对象是简单动态字符串
#define OBJ_ENCODING_INT 1     /* Encoded as integer */         //long类型的整数
#define OBJ_ENCODING_HT 2      /* Encoded as hash table */      //字典
#define OBJ_ENCODING_ZIPMAP 3  /* Encoded as zipmap */          //不在使用
#define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */  //双端链表,不在使用
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */         //压缩列表
#define OBJ_ENCODING_INTSET 6  /* Encoded as intset */          //整数集合
#define OBJ_ENCODING_SKIPLIST 7  /* Encoded as skiplist */      //跳跃表和字典
#define OBJ_ENCODING_EMBSTR 8  /* Embedded sds string encoding */   //embstr编码的简单动态字符串
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */   //由压缩列表组成的双向列表-->快速列表

每种类型的对象都至少使用了两种不同的编码,下面列出了每种对象可使用的编码方式。
来自网上
在这里插入图片描述

1.2.4. 对象的值

Redis 使用 redisObject 中的 ptr 属性来指向实际的数据对象,实际数据对象的类型和内容取决于对象的类型和编码方式。例如,对于字符串对象,ptr 指向字符串的字符数组,对于列表对象,ptr 指向列表的头节点。

所以这样来看,我们之前讲过的所有Redis的基本数据类型,其实底层创建的时候基本上都是。Redis 通过使用 redisObject 来统一表示不同类型的数据对象,并使用对象引用计数、共享对象、编码方式和实际值等机制来管理和优化数据对象的使用。而且使用 redisObject 可以帮助 Redis 实现高效的内存管理和数据存储。所以如果面试的花,能简略的答出来这一段内容的关键点,也算是有一定理解了。

2. 总结

redis使用自己实现的对象机制(redisObject)来实现类型判断、命令多态和基于引用次数的垃圾回收;redis会预分配一些常用的数据对象,并通过共享这些对象来减少内存占用,和避免频繁的为小对象分配内存。
最后我们来回答一下上面抛出的问题

2.1. redisObject对象如何实现数据共享和对象池技术?

数据共享技术:Redis 中的字符串对象是可以共享的,如果多个字符串对象的值相同,那么它们可以共享同一个 redisObject 对象。Redis 通过使用共享池来实现字符串对象的共享,共享池中存储了所有的共享字符串对象,每个共享字符串对象都有一个引用计数,当字符串对象不再被使用时,可以将它从共享池中删除。

对象池技术:Redis 中的对象池是用于存储 redisObject 对象的内存池,它可以有效地管理对象的内存,减少内存碎片和内存分配的开销。Redis 中的对象池使用两个栈来管理空闲的 redisObject 对象,一个是大对象栈,用于管理较大的对象,另一个是小对象栈,用于管理较小的对象。当需要分配新的 redisObject 对象时,Redis 会先从对象池中查找是否有空闲对象,如果有,则直接分配给新的对象,如果没有,则从系统中分配新的内存空间。

2.2. redisObject对象的大小是否会随着数据类型的不同而变化

Redis 中的 redisObject 对象的大小会随着数据类型的不同而变化。不同类型的 redisObject 对象所需要的内存空间是不同的,因此它们的大小也会不同。
以字符串对象为例,Redis 中的字符串对象包含一个 len 字段和一个 buf 字段,其中 len 字段表示字符串的长度,buf 字段表示字符串的实际内容。因此,字符串对象的大小等于 len 字段的大小加上 buf 字段的大小。而对于列表对象、哈希表对象、集合对象和有序集合对象等,它们的大小也会随着数据结构的复杂度和元素数量的不同而变化。
需要注意的是,Redis 中的 redisObject 对象还包含一些额外的字段,如 type、encoding、lru 和 refcount 等,这些字段也会占用一定的内存空间。因此,在计算 redisObject 对象的大小时,还需要考虑这些额外的字段所占用的内存空间。

2.3. Redis中的对象池技术如何管理内存?

Redis 中的对象池技术是一种用于管理内存的技术,它可以有效地减少内存碎片和内存分配的开销,提高 Redis 的内存使用效率。对象池技术可以分为两个部分:内存池和空闲对象管理。

内存池:Redis 中的对象池使用一块大的内存空间来存储 redisObject 对象。这个内存空间被称为内存池,它可以分为两个部分:大对象池和小对象池。大对象池用于管理较大的 redisObject 对象,而小对象池用于管理较小的 redisObject 对象。内存池中的每个 redisObject 对象都有一个固定的大小,这样就可以避免内存碎片的产生。

空闲对象管理:Redis 中的对象池使用两个栈来管理空闲的 redisObject 对象,一个是大对象栈,另一个是小对象栈。当需要分配新的 redisObject 对象时,Redis 会先从对象池中查找是否有空闲对象,如果有,则直接分配给新的对象,如果没有,则从系统中分配新的内存空间。

当 redisObject 对象不再被使用时,对象池会将这个对象放回对象池中,以便下次再次使用。这个过程会先将对象的实际数据清空,然后将对象放入对应的空闲对象栈中,同时更新对象的 refcount 字段,将其设置为 0。当空闲对象栈中的对象数量达到一定的阈值时,对象池会释放一部分内存,以便回收内存空间。
这种设计是大多数编程语言都喜欢使用的一种思想。

2.4.Redis中的共享池如何管理共享字符串对象?

共享池是用于管理共享字符串对象的内存池。共享字符串对象是指多个字符串对象的值相同,可以共享同一个 redisObject 对象。Redis通过使用共享池来实现字符串对象的共享,从而提高 Redis 的内存使用效率。 共享池中存储了所有的共享字符串对象,每个共享字符串对象都有一个引用计数。当创建新的字符串对象时,Redis 会先在共享池中查找是否存在相同值的共享字符串对象。如果存在,则将新的字符串对象的指针指向共享字符串对象的地址,并将共享字符串对象的引用计数加 1。如果不存在,则创建新的字符串对象,并将其加入共享池中。 当某个字符串对象不再被使用时,Redis 会将其从共享池中删除,并将其引用计数减 1。如果引用计数变为 0,则表示该字符串对象不再被任何其他对象所引用,可以将其释放并回收其所占用的内存。

这块有个坑 共享池中的每个共享字符串对象都是只读的,就类似于JAVA语言的String对象。如果需要修改一个共享字符串对象的值,那么需要先将其从共享池中拷贝出来,创建一个新的字符串对象,并将其值修改为新的值。这样就可以避免修改共享字符串对象的值对其他对象造成影响。

2.5. 如何判断一个字符串对象是否在共享池中?

可以通过 Redis 的一些命令,如 object encodingobject idletimedebug object 等,来判断一个字符串对象是否在共享池中。如果字符串对象是共享字符串对象,那么 Redis 会返回特定的结果,可以通过这些结果来判断字符串对象是否在共享池中。

3. Redis从入门到精通系列文章

《Redis从入门到精通【进阶篇】之消息传递发布订阅模式详解》
《Redis从入门到精通【进阶篇】之持久化 AOF详解》
《Redis从入门到精通【进阶篇】之持久化RDB详解》
《Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解》
《Redis从入门到精通【高阶篇】之底层数据结构快表QuickList详解》
《Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解》
《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
《Redis从入门到精通【进阶篇】之数据类型Stream详解和使用示例》
在这里插入图片描述
大家好,我是冰点,今天的Redis从入门到精通【进阶篇】之对象机制详解,全部内容就是这些。如果你有疑问或见解可以在评论区留言。

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

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

相关文章

vue项目打包并配置到iOS工程中

一、修改vue项目的配置文件 将config文件夹里面的index.js中的 assetsPublicPath的值修改为“./” Webpack.prod.conf.js 中output添加参数publicPath:./ 在webpack.base.conf.js里 publicPath: process.env.NODE_ENV 生产 ?./ config.build.assetsPublicPath :…

Compose编排工具应用

补充: Docker Compose 文件:Docker Compose 是一个用于定义和运行多个 Docker 容器的工具。它使用 YAML 文件格式来描述应用程序的各个组件和其配置。以下是一个简单的示例: 在上面的示例中,我们定义了两个服务:web 和…

SpringBoot 之实现 PDF 添加水印的方案

简介 PDF(Portable Document Format,便携式文档格式)是一种流行的文件格式,它可以在多个操作系统和应用程序中进行查看和打印。在某些情况下,我们需要对 PDF 文件添加水印,以使其更具有辨识度或者保护其版…

ChatGLM2-6B的P-Tuning微调

ChatGLM2-6B:https://github.com/THUDM/ChatGLM2-6B 模型地址:https://huggingface.co/THUDM/chatglm2-6b 详细步骤同:ChatGLM-6B的P-Tuning微调详细步骤及结果验证 环境可复用ChatGLM-6B(上述部署教程),…

简要介绍 | 知识蒸馏:轻量级模型的智慧之源

注1:本文系“简要介绍”系列之一,仅从概念上对知识蒸馏进行非常简要的介绍,不适合用于深入和详细的了解。 知识蒸馏:轻量级模型的智慧之源 A Gentle Introduction to Hint Learning & Knowledge Distillation | by LA Tran | …

Some about RMI

(备份防止忘掉) 一开始编译javac所有文件 这个问题概率遇到 解决方法: 然后java编译impl文件 直到出现bound in registry这一句 然后这个cmd不要关掉 重新在eclipse这个类的工作路径打开一个cmd 看到这个之后回到eclipse里面运行app这个文…

数据结构--树的性质

数据结构–树的性质 树的常考性质 常见考点 1 : 结点数 总度数 1 \color{red}常见考点1:结点数总度数1 常见考点1:结点数总度数1 结点的度 ―― 结点有几个孩子(分支) 树的度 ―― 各结点的度的最大值 m叉树 ―― 每个结点最多只能有m个孩子的树 常见考点 2 : 度为 m 的树、…

MySQL安装以及体系结构

1.简述mysql体系结构 MySQL 最重要、最与众不同的特性是它的存储引擎架构,这种架构的设计将查询处理 (Query Processing)及其他系统任务(Server Task)和数据的存储/提取相分离。这种 处理和存储分离的设计可以在使用时…

【简单认识LVS及LVS-NAT负载均衡群集的搭建】

文章目录 一、LVS群集简介1、群集的含义2、性能扩展方式3、群集的分类4、负载均衡群集架构1、负载均衡的结构 5、三种负载调度工作模式1、NAT模式2、TUN模式3、DR模式 二、LVS虚拟服务器1、Linux Virtual Server简介2、启用LVS虚拟服务3、LVS调度算法(1)…

YoloV5/YoloV7改进---注意力机制:高斯上下文变换器GCT,性能优于ECA、SE等注意力模块 | CVPR2021

目录 1.GCT介绍 实验结果 2.GCT引入到yolov5 2.1 加入common.py中: 2.2 加入yolo.py中: 2.3 yolov5s_GCT.yaml 2.4 yolov5s_GCT1.yaml 1.GCT介绍 论文:https://openaccess.thecvf.com/content/CVPR2021/papers/Ruan_Gaussian_Context_Tra…

Spring源码解析(二):bean容器的创建、默认后置处理器、扫描包路径bean

Spring源码系列文章 Spring源码解析(一):环境搭建 Spring源码解析(二): 目录 一、Spring源码基础组件1、bean定义接口体系2、bean工厂接口体系3、ApplicationContext上下文体系 二、AnnotationConfigApplicationContext注解容器1、创建bean工厂-beanFa…

计算机网络概述(三)

常见的计算机网络体系结构 OSI体系结构: 物理层→数据链路层→网络层→运输层→会话层→表示层→应用层 TCP/IP体系结构: 网络接口层→网际层→运输层→应用层 一般用户的设备都有TCP/IP协议用于连接因特网,TCP/IP的网络接口层并没有规定使用…

Linux基础+html和script一些基本语法

文章目录 linux 基础名字含义指令 html 语法style 样式属性样式标签属性颜色margin 边距ransform 旋转角度重复样式opacity 透明度div 方块元素box-shadow 阴影属性浮动 script获取节点onclick 点击触发setTimeout 定时器利用定时器实现 动画效果 javascript强弱语言区分parseI…

简单详细的MySQL数据库结构及yum和通用二进制安装mysql的方法

目录 mysql体系结构mysql的安装方法一,yum安装1,首先下载一个网络源仓库:2,然后安装 mysql-community-server3,启动mysqld 服务4,然后登录数据库5,初次登录要设置密码,而且不能太简单…

小型电子声光礼花器电子烟花爆竹电路设计

节日和庆典时燃放礼花,其绚丽缤纷的图案,热烈的爆炸声、欢乐的气氛,能给人们留下美好的印象,但有一定的烟尘污染和爆炸危险隐患。本电路可以模拟礼花燃放装置,达到声型兼备的效果,给人们在安全、环保的环境…

redis rehash

dict结构 dictEntry即键值对,每个桶就是dictEntry连接的链表 typedef struct dictEntry {void *key;union {void *val; // 自定义类型uint64_t u64;int64_t s64;double d;} v;struct dictEntry *next; } dictEntry;数据真正指向的地方 typedef struct dictht {di…

京东网站登录二维码显示不出来

环境: 360急速浏览器 Win10专业版 问题描述: 京东网站登录二维码显示不出来 解决方案: 1.打开安全卫士 2.功能大全找到断网急救箱 3.全面诊断一下有问题修复一下,重启浏览器解决

数字迷宫:探秘统计位数为偶数的奇妙世界

本篇博客会讲解力扣“1295. 统计位数为偶数的数字”的解题思路,这是题目链接。 统计位数是偶数的数据个数,关键在于如何统计一个整数的位数。方法是:对于一个整数n,每次/10,都会缩小一位,所以一直进行/10操…

【爬虫】AOI

目前几个大厂,高德百度腾讯,都支持POI爬取,而AOI是需要自己找接口的。 换言之,爬虫需谨慎 1 百度AOI 参考链接是: 这两个链接是选定范围爬取范围内选定类别的AOI 黑科技 | 百度地图抓取地块功能(上&#x…

DeepSpeed-Chat 打造类ChatGPT全流程 笔记二之监督指令微调

文章目录 系列文章0x0. 前言0x1. 🐕 Supervised finetuning (SFT) 教程翻译🏃 如何训练模型🏃 如何对SFT checkpoint进行评测?💁 模型和数据☀️来自OPT-1.3B及其SFT变体(使用不同微调数据)的提示示例☀️…