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

Redis设计与实现之数据库

目录

一、数据库

1、数据库的结构

2、 数据库的切换

3、 数据库键空间

4、键空间的操作

添加新键

删除键

更新键

取值

其他操作

5、 键的过期时间

6、过期时间的保存

7、设置生存时间 

8、过期键的判定

9、 过期键的清除

定时删除

惰性删除

定期删除

10、过期键的惰性删除策略

11、 过期键的定期删除策略

12、 过期键对 AOF 、RDB 和复制的影响

更新后的 RDB 文件

AOF 重写

复制

13、 数据库空间的收缩和扩展

二、 小结


一、数据库

本章将对 Redis 数据库的构造和实现进行讨论。

除了说明数据库是如何储存数据对象之外,本章还会讨论键的过期信息是如何保存,而 Redis 又是如何删除过期键的。

1、数据库的结构

Redis 中的每个数据库,都由一个 redis.h/redisDb 结构表示:

typedef struct redisDb {// 保存着数据库以整数表示的号码int id;// 保存着数据库中的所有键值对数据// 这个属性也被称为键空间(key space) dict *dict;// 保存着键的过期信息dict *expires;// 实现列表阻塞原语,如 BLPOP // 在列表类型一章有详细的讨论 dict *blocking_keys;dict *ready_keys;// 用于实现 WATCH 命令// 在事务章节有详细的讨论 dict *watched_keys;} redisDb;

下文将详细讨论 id 、dict 和 expires 三个属性,以及针对这三个属性所执行的数据库操作。

2、 数据库的切换

redisDb 结构的 id 域保存着数据库的号码。
这个号码很容易让人将它和切换数据库的 SELECT 命令联系在一起,但是,实际上,id 属性并不是用来实现 SELECT 命令,而是给 Redis 内部程序使用的。

当 Redis 服务器初始化时,它会创建出 redis.h/REDIS_DEFAULT_DBNUM 个数据库,并将所有数据库保存到 redis.h/redisServer.db 数组中,每个数据库的 id 为从 0 到 REDIS_DEFAULT_DBNUM - 1 的值。

当执行 SELECT number 命令时,程序直接使用 redisServer.db[number] 来切换数据库。

但是,一些内部程序,比如 AOF 程序、复制程序和 RDB 程序,需要知道当前数据库的号码, 如果没有 id 域的话,程序就只能在当前使用的数据库的指针,和 redisServer.db 数组中所 有数据库的指针进行对比,以此来弄清楚自己正在使用的是那个数据库。

以下伪代码描述了这个对比过程:

def PSEUDO_GET_CURRENT_DB_NUMBER(current_db_pointer): i=0for db_pointer in redisServer.db:if db_pointer == current_db_pointer:breaki += 1 return i

有了 id 域的话,程序就可以通过读取 id 域来了解自己正在使用的是哪个数据库,这样就不用 对比指针那么麻烦了。

3、 数据库键空间

因为 Redis 是一个键值对数据库(key-value pairs database),所以它的数据库本身也是一个字典(俗称 key space):

• 字典的键是一个字符串对象。

• 字典的值则可以是包括字符串、列表、哈希表、集合或有序集在内的任意一种 Redis 类型 对象。

在 redisDb 结构的 dict 属性中,保存着数据库的所有键值对数据。

下图展示了一个包含 number 、book 、message 三个键的数据库——其中 number 键是一个列 表,列表中包含三个整数值;book 键是一个哈希表,表中包含三个键值对;而 message 键则 指向另一个字符串:

4、键空间的操作

因为数据库本身是一个字典,所以对数据库的操作基本上都是对字典的操作,加上以下一些维护操作:

  • 更新键的命中率和不命中率,这个值可以用 INFO 命令查看;

  • 更新键的 LRU 时间,这个值可以用 OBJECT 命令来查看;

  • 删除过期键(稍后会详细说明);

  • 如果键被修改了的话,那么将键设为脏(用于事务监视),并将服务器设为脏(等待 RDB 保存);将对键的修改发送到 AOF 文件和附属节点,保持数据库状态的一致;

作为例子,以下几个小节会展示键的添加、删除、更新、取值等几个主要操作。

添加新键

添加一个新键对到数据库,实际上就是将一个新的键值对添加到键空间字典中,其中键为字符串对象,而值则是任意一种 Redis 类型值对象。

举个例子,如果数据库的目前状态如下图所示(和前面展示的数据库状态图一样):

 那么在客户端执行 SET date 2013.2.1 命令之后,数据库更新为下图状态:

删除键

删除数据库中的一个键,实际上就是删除字典空间中对应的键对象和值对象。

举个例子,如果数据库的目前状态如下图所示(和前面展示的数据库状态图一样):

那么在客户端执行 DEL message 命令之后,数据库更新为下图状态: 

更新键

当对一个已存在于数据库的键执行更新操作时,数据库释放键原来的值对象,然后将指针指向新的值对象。

举个例子,如果数据库的目前状态如下图所示(和前面展示的数据库状态图一样):

那么在客户端执行 SET message "blah blah" 命令之后,数据库更新为下图状态: 

取值

在数据库中取值实际上就是在字典空间中取值,再加上一些额外的类型检查:

• 键不存在,返回空回复;
• 键存在,且类型正确,按照通讯协议返回值对象;

• 键存在,但类型不正确,返回类型错误。

举个例子,如果数据库的目前状态如下图所示(和前面展示的数据库状态图一样):

当客户端执行 GET message 时,服务器返回 "hello moto" 。 当客户端执行 GET not-exists-key 时,服务器返回空回复。 当服务器执行 GET book 时,服务器返回类型错误。

其他操作

除了上面展示的键值操作之外,还有很多针对数据库本身的命令,也是通过对键空间进行处理来完成的:

• FLUSHDB 命令:删除键空间中的所有键值对。
• RANDOMKEY 命令:从键空间中随机返回一个键。 • DBSIZE 命令:返回键空间中键值对的数量。
• EXISTS 命令:检查给定键是否存在于键空间中。
• RENAME 命令:在键空间中,对给定键进行改名。

等等

5、 键的过期时间

在前面的内容中,我们讨论了很多涉及数据库本身、以及对数据库中的键值对进行处理的操作,但是,关于数据库如何保存键的过期时间,以及如何处理过期键这一问题,我们还没有讨论到。

通过 EXPIRE 、PEXPIRE 、EXPIREAT 和 PEXPIREAT 四个命令,客户端可以给某个存 在的键设置过期时间,当键的过期时间到达时,键就不再可用:

redis> SETEX key 5 value
OK
redis> GET key
"value"
redis> GET key // 5 秒过后 (nil)

命令 TTL 和 PTTL 则用于返回给定键距离过期还有多长时间:

redis> SETEX key 10086 value
OK
redis> TTL key
(integer) 10082
redis> PTTL key
(integer) 10068998

在接下来的内容中,我们将探讨和键的过期时间相关的问题:比如键的过期时间是如何保存 的,而过期键又是如何被删除的,等等。

6、过期时间的保存

在数据库中,所有键的过期时间都被保存在 redisDb 结构的 expires 字典里:

typedef struct redisDb { // ...dict *expires;// ...
} redisDb;

expires 字典的键是一个指向 dict 字典(键空间)里某个键的指针,而字典的值则是键所指 向的数据库键的到期时间,这个值以 long long 类型表示。

下图展示了一个含有三个键的数据库,其中 number 和 book 两个键带有过期时间:

Note: 为了展示的方便,图中重复出现了两次 number 键和 book 键。在实际中,键空间字典 的键和过期时间字典的键都指向同一个字符串对象,所以不会浪费任何空间。

7、设置生存时间 

Redis 有四个命令可以设置键的生存时间(可以存活多久)和过期时间(什么时候到期): • EXPIRE以秒为单位设置键的生存时间;
• PEXPIRE 以毫秒为单位设置键的生存时间;
• EXPIREAT 以秒为单位,设置键的过期 UNIX 时间戳;

• PEXPIREAT 以毫秒为单位,设置键的过期 UNIX 时间戳。

虽然有那么多种不同单位和不同形式的设置方式,但是 expires 字典的值只保存“以毫秒为单 位的过期 UNIX 时间戳” ,这就是说,通过进行转换,所有命令的效果最后都和 PEXPIREAT 命令的效果一样。

举个例子,从 EXPIRE 命令到 PEXPIREAT 命令的转换可以用伪代码表示如下:

def EXPIRE(key, sec):# 将 TTL 从秒转换为毫秒ms = sec_to_ms(sec)# 获取以毫秒计算的当前 UNIX 时间戳ts_in_ms = get_current_unix_timestamp_in_ms()# 毫秒 TTL 加上毫秒时间戳,就是 key 到期的时间戳 PEXPIREAT(ms + ts_in_ms, key)

其他函数的转换方式也是类似的。
作为例子,下图展示了一个 expires 字典示例,字典中 number 键的过期时间是 2013 年 2 月10 日(农历新年),而 book 键的过期时间则是 2013 年 2 月 14 日(情人节):

 这两个键的过期时间可能是用以上四个命令的任意一个设置的,但它们都以统一的格式被保存 在 expires 字典中。

8、过期键的判定

通过 expires 字典,可以用以下步骤检查某个键是否过期:

1. 检查键是否存在于expires字典:如果存在,那么取出键的过期时间;

2. 检查当前 UNIX 时间戳是否大于键的过期时间:如果是的话,那么键已经过期;否则, 键未过期。可以用伪代码来描述这一过程:

def is_expired(key): # 取出键的过期时间key_expire_time = expires.get(key)# 如果过期时间不为空,并且当前时间戳大于过期时间,那么键已经过期if expire_time is not None and current_timestamp() > key_expire_time:return True# 否则,键未过期或没有设置过期时间 return False

9、 过期键的清除

我们知道了过期时间保存在 expires 字典里,又知道了该如何判定一个键是否过期,现在剩下的问题是,如果一个键是过期的,那它什么时候会被删除? 这个问题有三种可能的答案:

  1. 定时删除:在设置键的过期时间时,创建一个定时事件,当过期时间到达时,由事件处理 器自动执行键的删除操作。

  2. 惰性删除:放任键过期不管,但是在每次从 dict 字典中取出键值时,要检查键是否过 期,如果过期的话,就删除它,并返回空;如果没过期,就返回键值。

  3. 定期删除:每隔一段时间,对expires字典进行检查,删除里面的过期键。

定时删除

定时删除策略对内存是最友好的:因为它保证过期键会在第一时间被删除,过期键所消耗的内 存会立即被释放。

这种策略的缺点是,它对 CPU 时间是最不友好的:因为删除操作可能会占用大量的 CPU 时间 ——在内存不紧张、但是 CPU 时间非常紧张的时候(比如说,进行交集计算或排序的时候), 将 CPU 时间花在删除那些和当前任务无关的过期键上,这种做法毫无疑问会是低效的。

除此之外,目前 Redis 事件处理器对时间事件的实现方式——无序链表,查找一个时间复杂度 为 O(N) ——并不适合用来处理大量时间事件。

惰性删除

惰性删除对 CPU 时间来说是最友好的:它只会在取出键时进行检查,这可以保证删除操作只 会在非做不可的情况下进行——并且删除的目标仅限于当前处理的键,这个策略不会在删除其 他无关的过期键上花费任何 CPU 时间。

惰性删除的缺点是,它对内存是最不友好的:如果一个键已经过期,而这个键又仍然保留在数 据库中,那么 dict 字典和 expires 字典都需要继续保存这个键的信息,只要这个过期键不被 删除,它占用的内存就不会被释放。

在使用惰性删除策略时,如果数据库中有非常多的过期键,但这些过期键又正好没有被访问的话,那么它们就永远也不会被删除(除非用户手动执行),这对于性能非常依赖于内存大小的 Redis 来说,肯定不是一个好消息。

举个例子,对于一些按时间点来更新的数据,比如日志(log),在某个时间点之后,对它们的访 问就会大大减少,如果大量的这些过期数据积压在数据库里面,用户以为它们已经过期了(已 经被删除了),但实际上这些键却没有真正的被删除(内存也没有被释放),那结果肯定是非常 糟糕。

定期删除

从上面对定时删除和惰性删除的讨论来看,这两种删除方式在单一使用时都有明显的缺陷:定 时删除占用太多 CPU 时间,惰性删除浪费太多内存。

定期删除是这两种策略的一种折中:

• 它每隔一段时间执行一次删除操作,并通过限制删除操作执行的时长和频率,籍此来减 少删除操作对 CPU 时间的影响。

• 另一方面,通过定期删除过期键,它有效地减少了因惰性删除而带来的内存浪费。 Redis 使用的策略

Redis 使用的过期键删除策略是惰性删除加上定期删除,这两个策略相互配合,可以很好地在 合理利用 CPU 时间和节约内存空间之间取得平衡。

因为前面已经说了这两个策略的概念了,下面两节就来探讨这两个策略在 Redis 中的具体实现。

10、过期键的惰性删除策略

实现过期键惰性删除策略的核心是 db.c/expireIfNeeded 函数——所有命令在读取或写入数 据库之前,程序都会调用 expireIfNeeded 对输入键进行检查,并将过期键删除:

比如说,GET 命令的执行流程可以用下图来表示: 

expireIfNeeded 的作用是,如果输入键已经过期的话,那么将键、键的值、键保存在 expires 字典中的过期时间都删除掉。

用伪代码描述的 expireIfNeeded 定义如下:

def expireIfNeeded(key):# 对过期键执行以下操作 。。if key.is_expired():# 从键空间中删除键值对db.dict.remove(key) # 删除键的过期时间db.expires.remove(key)# 将删除命令传播到 AOF 文件和附属节点 propagateDelKeyToAofAndReplication(key)

11、 过期键的定期删除策略

对过期键的定期删除由 redis.c/activeExpireCycle 函执行:每当 Redis 的例行处理程序 serverCron 执行时,activeExpireCycle 都会被调用——这个函数在规定的时间限制内,尽 可能地遍历各个数据库的 expires 字典,随机地检查一部分键的过期时间,并删除其中的过期键。

整个过程可以用伪代码描述如下:

def activeExpireCycle():# 遍历数据库(不一定能全部都遍历完,看时间是否足够)for db in server.db:# MAX_KEY_PER_DB 是一个 DB 最大能处理的 key 个数 # 它保证时间不会全部用在个别的 DB 上(避免饥饿) i=0while (i < MAX_KEY_PER_DB):# 数据库为空,跳出 while ,处理下个 DB if db.is_empty(): break# 随机取出一个带 TTL 的键key_with_ttl = db.expires.get_random_key()# 检查键是否过期,如果是的话,将它删除 if is_expired(key_with_ttl):db.deleteExpiredKey(key_with_ttl)# 当执行时间到达上限,函数就返回,不再继续 # 这确保删除操作不会占用太多的 CPU 时间if reach_time_limit(): returni += 1

12、 过期键对 AOF 、RDB 和复制的影响

前面的内容讨论了过期键对 CPU 时间和内存的影响,现在,是时候说说过期键在 RDB 文件、AOF 文件、AOF 重写以及复制中的影响了:
过期键会被保存在更新后的 RDB 文件、AOF 文件或者重写后的 AOF 文件里面吗? 附属节点会会如何处理过期键?处理的方式和主节点一样吗? 以上这些问题就是本节要解答的。

更新后的 RDB 文件

在创建新的 RDB 文件时,程序会对键进行检查,过期的键不会被写入到更新后的 RDB 文件中。
因此,过期键对更新后的 RDB 文件没有影响。

AOF 文件 在键已经过期,但是还没有被惰性删除或者定期删除之前,这个键不会产生任何影响,AOF 文件也不会因为这个键而被修改。

当过期键被惰性删除、或者定期删除之后,程序会向 AOF 文件追加一条 DEL 命令,来显式地 记录该键已被删除。

举个例子,如果客户端使用 GET message 试图访问 message 键的值,但 message 已经过期了, 那么服务器执行以下三个动作:

1. 从数据库中删除message;
2. 追加一条 DEL message 命令到 AOF 文件; 3. 向客户端返回NIL。

AOF 重写

和 RDB 文件类似,当进行 AOF 重写时,程序会对键进行检查,过期的键不会被保存到重写后的 AOF 文件。
因此,过期键对重写后的 AOF 文件没有影响。

复制

当服务器带有附属节点时,过期键的删除由主节点统一控制:

  • 如果服务器是主节点,那么它在删除一个过期键之后,会显式地向所有附属节点发送一

    个 DEL 命令。

  • 如果服务器是附属节点,那么当它碰到一个过期键的时候,它会向程序返回键已过期的 回复,但并不真正的删除过期键。因为程序只根据键是否已经过期、而不是键是否已经被 删除来决定执行流程,所以这种处理并不影响命令的正确执行结果。当接到从主节点发来 的 DEL 命令之后,附属节点才会真正的将过期键删除掉。

附属节点不自主对键进行删除是为了和主节点的数据保持绝对一致,因为这个原因,当一个过 期键还存在于主节点时,这个键在所有附属节点的副本也不会被删除。

这种处理机制对那些使用大量附属节点,并且带有大量过期键的应用来说,可能会造成一部分 内存不能立即被释放,但是,因为过期键通常很快会被主节点发现并删除,所以这实际上也算 不上什么大问题。

13、 数据库空间的收缩和扩展

因为数据库空间是由字典来实现的,所以数据库空间的扩展/收缩规则和字典的扩展/收缩规则完全一样,具体的信息可以参考《字典》章节。

因为对字典进行收缩的时机是由使用字典的程序决定的,所以 Redis 使用 redis.c/tryResizeHashTables 函数来检查数据库所使用的字典是否需要进行收缩:每次 redis.c/serverCron 函数运行的时候,这个函数都会被调用。

tryResizeHashTables 函数的完整定义如下:

/*
* 对服务器中的所有数据库键空间字典、以及过期时间字典进行检查,
* 看是否需要对这些字典进行收缩。 *
* 如果字典的使用空间比率低于 REDIS_HT_MINFILL
* 那么将字典的大小缩小,让 USED/BUCKETS 的比率 <= 1 
*/
void tryResizeHashTables(void) { int j;for (j = 0; j < server.dbnum; j++) {// 缩小键空间字典if (htNeedsResize(server.db[j].dict))dictResize(server.db[j].dict);// 缩小过期时间字典if (htNeedsResize(server.db[j].expires))dictResize(server.db[j].expires);} 
}

二、 小结

  • 数据库主要由dict和expires两个字典构成,其中dict保存键值对,而expires则

    保存键的过期时间。

  • 数据库的键总是一个字符串对象,而值可以是任意一种 Redis 数据类型,包括字符串、哈 希、集合、列表和有序集。

  • expires 的某个键和 dict 的某个键共同指向同一个字符串对象,而 expires 键的值则 是该键以毫秒计算的 UNIX 过期时间戳。

  • Redis 使用惰性删除和定期删除两种策略来删除过期的键。

  • 更新后的 RDB 文件和重写后的 AOF 文件都不会保留已经过期的键。

  • 当一个过期键被删除之后,程序会追加一条新的 DEL 命令到现有 AOF 文件末尾。

  • 当主节点删除一个过期键之后,它会显式地发送一条DEL命令到所有附属节点。

  • 附属节点即使发现过期键,也不会自作主张地删除它,而是等待主节点发来DEL命令, 这样可以保证主节点和附属节点的数据总是一致的。

  • 数据库的dict字典和expires字典的扩展策略和普通字典一样。它们的收缩策略是:当 节点的填充百分比不足 10% 时,将可用节点数量减少至大于等于当前已用节点数量。

相关文章:

Redis设计与实现之数据库

目录 一、数据库 1、数据库的结构 2、 数据库的切换 3、 数据库键空间 4、键空间的操作 添加新键 删除键 更新键 取值 其他操作 5、 键的过期时间 6、过期时间的保存 7、设置生存时间 8、过期键的判定 9、 过期键的清除 定时删除 惰性删除 定期删除 10、过期…...

如何在Eclipse中安装WindowBuilder插件,详解过程

第一步&#xff1a;找到自己安装eclipse的版本&#xff0c;在Help-关于eclipse里面&#xff0c;即Version 第二步&#xff1a;去下面这个网站找到对应的 link&#xff08;Update Site&#xff09;&#xff0c;这一步很重要&#xff0c;不然版本下载错了之后还得删除WindowBuil…...

node.js mongoose schemaTypes

目录 官方文档 简介 SchemaType 示例 配置SchemaType规则 通用规则 特定schemaType规则 String Number Date Map monggose会根据shcemaType将文档值转换成指定的类型 官方文档 Mongoose v8.0.3: SchemaTypes 简介 SchemaTypes是在使用Mongoose时&#xff0c;用于…...

论文解读:On the Integration of Self-Attention and Convolution

自注意力机制与卷积结合&#xff1a;On the Integration of Self-Attention and Convolution(CVPR2022) 引言 1&#xff1a;卷积可以接受比较大的图片的&#xff0c;但自注意力机制如果图片特别大的话&#xff0c;运算规模会特别大&#xff0c;即上图中右边(卷积)会算得比较快…...

【Spring】15 ApplicationContextAware 接口

文章目录 1. 简介2. 作用3. 使用3.1 创建并实现接口3.2 配置 Bean 信息3.3 创建启动类3.4 启动 4. 应用场景总结 Spring 框架提供了许多回调接口&#xff0c;用于在 Bean 的生命周期中执行特定的操作。ApplicationContextAware 接口是其中之一&#xff0c;它允许 Bean 获取对 A…...

Android 版本控制工具--Git

要在Android中使用Git&#xff0c;需要进行以下步骤&#xff1a; 安装Git&#xff1a;首先在你的开发环境中安装Git。在Windows中&#xff0c;你可以从官方网站&#xff08;https://git-scm.com/downloads&#xff09;上下载Git的可执行文件并进行安装。在Mac上&#xff0c;你可…...

Wireshark高级网络安全分析

第一章&#xff1a;Wireshark基础及捕获技巧 1.1 Wireshark基础知识回顾 1.2 高级捕获技巧&#xff1a;过滤器和捕获选项 1.3 Wireshark与其他抓包工具的比较 第二章&#xff1a;网络协议分析 2.1 网络协议分析&#xff1a;TCP、UDP、ICMP等 2.2 高级协议分析&#xff1a;HTTP…...

llvm后端之DAG设计

llvm后端之DAG设计 引言1 核心类设计2 类型系统2.1 MVT::SimpleValueType2.2 MVT2.3 EVT 3 节点类型 引言 llvm后端将中端的IR转为有向无环图&#xff0c;即DAG。如下图&#xff1a; 图中黑色箭头为数据依赖&#xff1b;蓝色线和红色线为控制依赖。蓝色表示指令序列化时两个节…...

反序列化 [SWPUCTF 2021 新生赛]ez_unserialize

打开题目 查看源代码 得到提示&#xff0c;那我们用御剑扫描一下看看 我们知道有个robots.txt&#xff0c;访问一下得到 那我们便访问一下 cl45s.php看看 得到网站源代码 <?phperror_reporting(0); show_source("cl45s.php");class wllm{public $admin;public …...

centos(linux)安装jenkins

官网&#xff1a;https://pkg.jenkins.io/redhat/ 安装官网进行操作&#xff1a; sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.reposudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io-2023.key若出现如下错误&#xff1a; …...

Wireshark统计和可视化

第一章&#xff1a;Wireshark基础及捕获技巧 1.1 Wireshark基础知识回顾 1.2 高级捕获技巧&#xff1a;过滤器和捕获选项 1.3 Wireshark与其他抓包工具的比较 第二章&#xff1a;网络协议分析 2.1 网络协议分析&#xff1a;TCP、UDP、ICMP等 2.2 高级协议分析&#xff1a;HTTP…...

高通平台开发系列讲解(SIM卡篇)SIM软件架构介绍

文章目录 一、SIM软件架构二、MMG SDI Task三、GSTK Task四、Simlock Task沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇文章将介绍SIM的相关组件。 SIM软件架构: SIM软件架构指的是与SIM卡(Subscriber Identity Module,订阅者身份模块)相关的软件系统设计和…...

音频筑基:瞬态、基音、偏噪信号类型分析

音频筑基&#xff1a;瞬态、基音、偏噪信号类型分析 是什么深入理解从编码角度看&#xff0c;基音信号编码通常会有啥问题&#xff1f;在频域感知编码过程中&#xff0c;瞬态信号会有啥问题&#xff1f;如何解决&#xff1f;瞬态信号场景下&#xff0c;5/10ms帧长编码有啥区别&…...

HarmonyOS ArkTS 中DatePicker先择时间 路由跳转并传值到其它页

效果 代码 代码里有TextTimerController 这一种例用方法较怪&#xff0c;Text ,Button Datepicker 的使用。 import router from ohos.router’则是引入路由模块。 import router from ohos.router Entry Component struct TextnewClock {textTimerController: TextTimerContr…...

Axure RP 8 for Mac/win中文版:打造完美交互式原型设计体验

Axure RP 8&#xff0c;一款引领潮流的交互式原型设计工具&#xff0c;为设计师提供了无限的可能性&#xff0c;让他们能够创造出逼真的原型&#xff0c;从而更好地展示和测试他们的设计。 Axure RP 8拥有丰富的功能和工具&#xff0c;让设计师可以轻松地创建出复杂的交互式原…...

迪文屏开发保姆级教程——页面键盘

迪文屏页面键盘保姆级教程。 本篇文章主要介绍了在DGBUS平台上使用页面键盘的步骤。 迪文屏官方开发指南PDF&#xff1a;&#xff08;不方便下载的私聊我发给你&#xff09; https://download.csdn.net/download/qq_21370051/88647174?spm1001.2014.3001.5503https://downloa…...

Unity的UI界面——Text/Image

编辑UI界面时&#xff0c;要先切换到2d界面 &#xff08;3d项目的话&#xff09; 1.Text控件 Text控件的相关属性&#xff1a; Character:&#xff08;字符&#xff09; Font&#xff1a;字体 Font Style&#xff1a;字体样式 Font Size&#xff1a;字体大小 Line Spac…...

sklearn和tensorflow的理解

人工智能的实现是基于机器学习&#xff0c;机器学习的一个方法是神经网络&#xff0c;以及各种机器学习算法库。 有监督学习&#xff1a;一般数据构成是【特征值目标值】 无监督学习&#xff1a;一般数据构成是【特征值】 Scikit-learn(sklearn)的定位是通用机器学习库&…...

css中BFC

css BFC BFC具有以下特性创建BFC的方式有多种BFC的应用场景和作用 扩展&#xff1a; CSS动画 transition: 过渡动画animation / keyframestransform都有哪些属性 举例 css BFC BFC&#xff0c;即块级格式化上下文&#xff08;Block Formatting Context&#xff09;&#xf…...

华为OD机试 - 小朋友来自多少小区(Java JS Python C)

题目描述 幼儿园组织活动,老师布置了一个任务: 每个小朋友去了解与自己同一个小区的小朋友还有几个。 我们将这些数量汇总到数组 garden 中。 请根据这些小朋友给出的信息,计算班级小朋友至少来自几个小区? 输入描述 输入:garden[] = {2, 2, 3} 输出描述 输出:7 备…...

前端:NPM的介绍和使用

一、NPM的介绍 NPM是Node.js的包管理器&#xff0c;用于管理Node.js的包NPM提供了方便的方式来安装、管理和分享Node.js的包 二、NPM的使用 1. 安装NPM 要使用NPM&#xff0c;首先需要安装Node.js。安装完成后&#xff0c;可以在命令行中运行以下命令来检查Node.js和NPM是否…...

力扣57. 插入区间

双指针法 思路&#xff1a; 用待插入区间左右边界初始化双指针 left 和 right&#xff1b;遍历待归并区间&#xff1a; 如果元素整体边界在 [left, right] 左侧&#xff08;item[1] < left&#xff09;&#xff0c;则将给元素插入结果数组中&#xff1b;如果元素整体边界在…...

Linux c++开发-11-Socket TCP编程简单案例

服务端&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <sys/types.h>#include <errno.h>int main(void) {//1.socketint server_sock socket(A…...

ros2机器人常规控制流程

The joint_state_publisher reads the robot_description parameter from the parameter server, finds all of the non-fixed joints and publishes a JointState message with all those joints defined.也就是说如果我们不需要控制机器人运动&#xff0c;只需要一个节点就可…...

分布式全局ID之雪花算法

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 雪花算法 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、什么是雪花算法&#xff1f…...

拿到服务器该做的事和升级docker engine

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginsudo -i # 切换到 root 用户apt update -y # 升级 packagesapt install wget curl sudo vim git -y # Debian 系统比较干净&#xff0c;安装常用的软件 安装docker …...

【VScode和Leecode的爱恨情仇】command ‘leetcode.signin‘ not found

文章目录 一、关于command ‘leetcode.signin‘ not found的问题二、解决方案第一&#xff0c;没有下载Nodejs&#xff1b;第二&#xff0c;有没有在VScode中配置Nodejs第三&#xff0c;力扣的默认在VScode请求地址中请求头错误首先搞定配置其次搞定登入登入方法一&#xff1a;…...

mangokit:golang web项目管理工具,使用proto定义http路由和错误

文章目录 前言1、mangokit介绍1.1 根据proto文件生成http路由1.2 根据proto文件生成响应码1.3 使用wire来管理依赖注入 2、mangokit实现2.1 protobuf插件开发2.2 mangokit工具 3、使用示例3.1 创建新项目3.2 添加新的proto文件3.3 代码生成 前言 在使用gin框架开发web应用时&a…...

微信小程序实现一个简单的登录功能

微信小程序实现一个简单的登录功能 功能介绍login.wxmllogin.jsuserInfo.wxmluserInfo.js解析 功能介绍 微信小程序实现一个简单的登录功能。包括一个登录页面和一个用户信息展示页面。在登录页面中输入用户名和密码&#xff0c;点击登录按钮进行验证&#xff0c;如果验证成功&…...

whisper深入-语者分离

文章目录 学习目标&#xff1a;如何使用whisper学习内容一&#xff1a;whisper 转文字1.1 使用whisper.load_model()方法下载&#xff0c;加载1.2 使用实例对文件进行转录1.3 实战 学习内容二&#xff1a;语者分离&#xff08;pyannote.audio&#xff09;pyannote.audio是huggi…...

为什么使用html5网站/沈阳seo优化

常见的集合如下:在集合框架中&#xff0c;有些类是线程安全的&#xff0c;这些都是jdk1.1中的出现的。在jdk1.2之后&#xff0c;就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类&#xff1a;vector&#xff1a;就比arraylist多了个同步化机制(线程安全)&#xff…...

2023年免费进入b站/免费域名注册平台有哪些

学习web编程的方法&#xff1a;1、学习html和css&#xff1b;2、学习javascript&#xff1b;3、了解web服务器&#xff1b;4、学习一门服务器端脚本语言&#xff1b;5、学习数据库及SQL语法&#xff1b;6、学习web框架。如何学习web开发&#xff0c;需要掌握哪些方面&#xff1…...

网站设计的概述/镇江网站建设方案

[b]存储数据有两种基本方法&#xff1a;保存到普通文件&#xff0c;或者保存到数据库中。[/b] [b]数据写入&#xff1a;[/b] [list] [*]1、打开文件。如果文件不存在&#xff0c;需要先创建它。 [*]2、将数据写入这个文件。 [*]3、关闭这个文件。 [/list] [b]数据读出&#xff…...

长沙网络安全公司/手机端关键词排名优化

xampp-建站集成软件包专门用来建设本地电脑的php运行环境&#xff0c;用来测试php网站代码&#xff0c;这款xampp官方版包括了最新版本的ApacheMySQLPHPPERL集成安装包。支持多语言&#xff1a;英文、简体中文、繁体中文、韩文、俄文、日文等。XAMPP实际上在以下几个方面大放光…...

网站怎么做seo_/搜索网站的浏览器

2月8日&#xff0c;据外媒报道&#xff0c;在科技初创企业蓬勃发展的印度&#xff0c;有迹象表明轻松获得资金的市场环境正在发生改变。 在过去一年中的大部分时间里&#xff0c;印度快餐递送初创企业TinyOwl Technology Pvt.每单买卖都出现亏损&#xff0c;为了获得快速扩张&a…...

thinkphp企业网站开发/网络推广渠道有哪些

比如下面的代码中实现了一个只能转换User对象的MessageConverter&#xff0c;底层使用的是FastJson&#xff0c;在进行发送消息时重置了user的name属性&#xff0c;加上了t-前缀。 然后为了使它生效&#xff0c;我们需要把它定义为一个bean&#xff0c;并标注StreamMessageConv…...