Redis系列1:深刻理解高性能Redis的本质

Redis系列2:数据持久化提高可用性

Redis系列3:高可用之主从架构

Redis系列4:高可用之Sentinel(哨兵模式)

Redis系列5:深入分析Cluster 集群模式

追求性能极致:Redis6.0的多线程模型

追求性能极致:客户端缓存带来的革命

Redis系列8:Bitmap实现亿万级数据计算

Redis系列9:Geo 类型赋能亿级地图位置计算

Redis系列10:HyperLogLog实现海量数据基数统计

Redis系列11:内存淘汰策略

Redis系列12:Redis 的事务机制

Redis系列13:分布式锁实现

Redis系列14:使用List实现消息队列

Redis系列15:使用Stream实现消息队列

Redis系列16:聊聊布隆过滤器(原理篇)

Redis系列17:聊聊布隆过滤器(实践篇)

Redis系列18:过期数据的删除策略

Redis系列19:LRU内存淘汰算法分析

Redis系列20:LFU内存淘汰算法分析

Redis系列21:缓存与数据库的数据一致性讨论

Redis系列22:Redis 的Pub/Sub能力

1 介绍

Redis是我们在业务开发中很重要的一个辅助,能够极大提高我们系统的运行效率,为后端的存储服务减少压力,提升用户使用体验。

但是作为一个辅助提升速度的组件,如果自己存在请求延迟的情况,那将是一个巨大的灾难,可能引起整条业务链路的雪崩。

在我以往的博客里面,也有过相应的案例,比如 《架构与思维:一次缓存雪崩的灾难复盘》。

但在实际业务场景中,可能有更加复杂的原因导致Redis访问效率变慢,下面我们详细来分析下。

2 发现和监测Redis的慢执行

2.1 如何判断Redis变慢了

在之前的章节中,我们根据官网的资料有过这样的结论:

在较高的配置基准下(比如 8C 16G +),在连接数为0~10000的时候,最高QPS可达到120000。Redis以超过60000个连接为基准,仍然能够在这些条件下维持50000个q/s,体现了超高的性能。下图中横轴是连接数,纵轴是QPS。

可见,Redis的性能和流量可抗性是极其高的,从客户端request发出到接受到response,这个处理过程时间是极短的,一般是微秒级别。

而对比Redis出现性能瓶颈的时候,就会有比较异常的表现,如达到几秒甚至几十秒,这时候我们就可以认定 Redis 性能变差了,需要去优化。

感知到 Redis的变慢了,接下来我们要做的就是验证和确认,这样才能有针对性的进行优化。

我们通过以下方法进行验证和分析。

2.1 基线延迟测试

redis-cli 提供了一个指令选项 --intrinsic-latency,用于监测和统计某个时间段内Redis的最大延迟。这个选项可以用来评估Redis本身的性能,并且可以作为Redis的基准性能。

使用--intrinsic-latency选项需要指定时长,例如120秒。在指定的时间段内,redis-cli会记录每个秒级的最大延迟。这个最大延迟可以反映出Redis本身的性能,不受网络或其他外部因素的影响。

你可以通过以下命令使用--intrinsic-latency选项:

redis-cli --intrinsic-latency 120

执行该命令后,redis-cli会输出在120秒内的最大延迟统计信息。

需要注意的是,--intrinsic-latency选项从Redis的2.8.7版本开始支持。如果你使用的是较早的版本,可能无法使用该选项。

redis-cli --intrinsic-latency 120
Max latency so far: 5 microseconds.
Max latency so far: 14 microseconds.
Max latency so far: 33 microseconds.
Max latency so far: 52 microseconds.
Max latency so far: 70 microseconds.
Max latency so far: 130 microseconds.
Max latency so far: 272 microseconds.
Max latency so far: 879 microseconds.
Max latency so far: 1079 microseconds.
Max latency so far: 1665 microseconds.
Max latency so far: 1665 microseconds.

可以看到,当前运行的最大延迟是 1665 微秒,所以基线延迟的性能是 1665 (约 1.6 毫秒)微秒。

可以在终端上连接Redis的服务端进行测试,避免客户端测试因为网络的影响导致差异较大。

可以通过 -h host -p port 来连接到服务端。

redis-cli --latency -h `host` -p `port`

2.2 监控慢指令

在算法设计中,最优的时间复杂度是O(1) 和 O(log N)。

一样的 ,Redis官方也尽量自身的操作指令尽量的高效,尽量节省时间复杂度。但是涉及到集合操作、全量的复杂度一般为O(N),

  • 集合全量查询:HGETALL、SMEMBERS
  • 集合的聚合操作:SORT、LREM、 SUNION
  • SORTEDSET类型命令:ZDELRANGEBYSCORE

排查是否使用了慢指令,可以用如下几种方式:

  • 使用一些工具进行操作的延时监控,如 latency-monitor
  • 通过查询 Redis 的慢日志来分析执行慢查询的操作(下面会详细说到)

如果只是简单判断是否使用了慢速查询,还可以使用命令 top、htop、prstat 等检查 Redis 主进程的 CPU 消耗即可

2.3 监控慢日志

在 Redis 中,slowlog 是一个用于查询和记录执行时间较长的命令的命令。它可以帮助你找出哪些命令的执行时间超过了设定的阈值,并且将这些命令记录下来,以便后续分析和优化。

默认情况下命令执行时间超过 10ms 就会被记录到日志,这个只记录执行时间,摒弃了 io 往返或者网络延迟引起的响应慢部分。

如果你想修改慢查询的时间阈值,自定义慢查询的耗时标准,可以执行如下命令:

redis-cli CONFIG SET slowlog-log-slower-than 3330

这边为什么使用 3330 ,是因为我们采用上面基线延迟测试值的double。

slowlog 命令的基本语法如下:

slowlog get [count]

其中,count 是一个可选参数,表示要返回的 slow log 的数量。如果不指定 count,则默认返回最近的 slow log。

当执行 slowlog get 命令时,Redis 会返回最近的一些 slow log,每个 slow log 包含以下信息:

  • unique ID:该 slow log 的唯一 ID。
  • 时间戳:该 slow log 记录的时间戳。
  • 命令:执行了哪些命令。
  • 执行时间:执行该命令所花费的时间(以微秒为单位)。

    你可以通过 slowlog get 命令来查看最近的 slow log,以便找出需要优化的命令。此外,你还可以通过 slowlog-max-len 参数来设置 slow log 的最大长度,以避免日志过多占用过多内存。
# 举例:读取最近2个慢查询
127.0.0.1:6381> SLOWLOG get 2
1) 1) (integer) 17
2) (integer) 1693641198
3) (integer) 5427
4) 1) "hgetall"
2) "all.uer_info"
1) 1) (integer) 18
2) (integer) 1693641217
3) (string) "GET"
4) (integer) 3771

第一个 HGET 命令,共 4 个字段:

  • 字段 1:代表 slowlog 出现的序号,服务启动后递增加码,当前为 17。
  • 字段 2:查询时的 Unix 时间戳。
  • 字段 3:查询执行的时间数(微秒),当前值5472(5.472微秒) 比 3330多,所以被记录下来。
  • 字段 4: 表示查询的命令和参数, 如 hgetall all.user_info。

    这样的做法是输出慢查询,提供开发同学排查的方向。

3 解决Redis慢执行问题

根据我们之前的知识,Redis 的数据读写这个主操作是由单线程执行,如果被影响,导致阻塞,那么性能就会大大降低。

所以,如何避免主线程阻塞,是我们解决Redis慢执行的一个关键因素。以下从一个方向

3.1 网络通信延迟

互联网时代,客户端访问Redis服务端的时候很可能回到网络延迟较高,这样,客户端连接并请求的的效率就会变低。

如果是多个数据中心或者多网络分区的场景(两地三中心、异地多活),这种情况就更明显,毕竟数据在网络中传输都是视距离时延的。

通过 TCP/IP 连接或 Unix 域连接连接到 Redis,1 Gbit/s 的网络延迟大约为 200 us。

从下面这个图看到往返时间RTT(Round trip time),执行过程为:

  • 发送命令
  • 命令进入队列,待执行
  • 执行命令
  • 返回执行结果



    上面的图明显有效节约了RTT的次数,提高了效率。类似MGET和MSET等命令是Redis中用于批量操作多个key-value的命令,而Redis的很多其他命令,

    如 hgetall,不支持批量操作,需要消耗 N 次 RTT ,这个时候需要 pipeline 来解决这个问题。

    Redis pipeline 将多个命令连接在一起来减少网络响应往返次数。

3.2 慢指令导致的延迟

我们上面与分析过慢指令,在算法设计中,最优的时间复杂度是O(1) 和 O(log N)。所以当我们确认了有慢查询指令。可以通过以下两种方式解决:

  • 在 Cluster 集群中,复杂度高于O(1) 和 O(log N)的操作使用Slava从库执行,大部分复杂执行都是非写的,所以应该要避免阻塞主线程。当然,在Client执行也是可以的。
  • 使用高效命令代替慢执行的命令,同时避免单次查询大量数据,采用增量获取的办法(参考 SCAN、SSCAN、HSCAN、ZSCAN)。
  • 生产环境中禁用KEYS 命令,它在调试的时候会遍历所有的键值对,操作延时较高。

3.3 Fork 生成 RDB 导致的延迟

我们在数据持久化的篇章中,说过数据持久化的一些办法,包括RDB内存快照和AOF日志。使用的不合理,也会照成Redis的性能大打折扣。

生成 RDB 快照(参考这篇 《Redis系列2:数据持久化提高可用性》),Redis 必须 fork 后台进程,

做了fork操作之后,实际是拆分了执行出去,因为在主线程中执行,所以会导致性能降低,操作延迟。

在Redis 中可以使用操作系统的 COW(Copy On Write,多进程写时复制技术) 来快速持久化,减少内存占用。



Redis在执行 bgsave 时,涉及到内存和磁盘的分配和复制,并且从库加载 RDB 期间无法提供读写服务,为了保障高效率,

主库的数据量大小尽量控制在 2~4G 左右,超过4G,会让从库加载效率变慢,从而影响业务操作。

3.4 AOF 文件系统或 RDB 大内存页问题,包括 AOF 持久化阻塞、大内存页等

Linux 2.6.38 版本之后开始支持内存大页,最大可以支持2MB的内存页分配,而之前的常规页是按照4KB来分配的。

这样的话,会导致Redis本身的一些持久化操作的问题,(参考这篇 《Redis系列2:数据持久化提高可用性》)。

  • Redis 使用了 fork 生成 RDB 持久化, COW在数据被修改的时候,会复制一份数据。内存页太大的话,即使客户端修改的量很小,也会复制2MB的大页内存,导致性能变慢。
  • AOF 日志存储了 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。如果内存页那太大,单次重放(replay)的内容过多,也会导致性能变慢

可以使用指令来disable Linux 内存大页:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

3.5 操作系统 Swap 操作问题,包括内存磁盘数据转换、内存清理等

Swap是操作系统中的一种虚拟内存技术,用于在物理内存不足时将一部分数据从物理内存中移动到硬盘上,以释放物理内存空间,避免系统因为内存不够而导致的 oom 情况。Swap操作包括“换出”(swap out)和“换入”(swap in)两个过程。

  • Swap out是指将一部分数据从物理内存中移动到交换空间(swap space)中,以释放物理内存空间。当操作系统需要更多的内存空间时,它会根据一定的算法来决定哪些数据应该被移动到交换空间中。这些数据通常是最近最少使用的或者最不可能被再次使用的。
  • Swap in是指将一部分数据从交换空间中移动到物理内存中。当操作系统需要访问被移动到交换空间中的数据时,它会根据一定的算法来决定哪些数据应该被移动到物理内存中。这些数据通常是最近被访问的或者最可能被再次访问的。

Swap操作可以帮助操作系统在物理内存不足时继续运行程序,但是过度的swap操作可能会导致系统性能下降,因为硬盘访问速度比物理内存慢得多。因此,合理配置和管理swap空间对于系统性能优化非常重要。

通常建议将swap空间设置为物理内存的1.5到2倍,并且应该避免在swap空间中频繁进行大量的读写操作。

既然swap的操作引发是由于内存空间不够导致的操作,那看看我们的Redis里面有哪些操作会引起这类行为:

  • 使用超额的内存,比可用内存更多
  • 再比如上面说的那几点:RDB Fork操作以及大文件生成,AOF日志记录和指令同步。都可能导致大量的内存占用,触发了 swap。

3.5.1 对swap导致的性能问题进行排查

#  获取Redis 实例的进程ID(pid):
$ redis-cli info | grep process_id
process_id:12893 # 根据进程进入 /proc 文件系统目录:
cd /proc/12893 # 打开 smaps 的文件,查找所有文件中所有的 swap 操作:
# 这边可以看到,当使用内存达到810554 kb 时,swap内存达到37kb。
$ cat smaps | egrep '^(Swap|Size)'
Size: 241 kB
Swap: 0 kB
Size: 172 kB
Swap: 0 kB
Size: 810554 kB
Swap: 37 kB

如果 Swap 是 0 kb,或者小量的kb,应该都是正常的。但当出现百 M,甚至 GB 级别的 swap 大小时,内存就明显吃紧了,大概率会导致线上请求变慢。

可以用如下办法进行解决:

  • 资源补充:内存进行扩容。
  • 单一职责原则:Redis在独占的主机上运行,避免其他高内存占用服务的资源抢占。
  • 分治理念:增加 Cluster 集群的数量进行分担,减少单个实例所需的内存消耗。

3.6 AOF 的写回策略为 always,导致每个操作都要同步刷回磁盘

为了保证数据可靠性,Redis 使用 AOF 和 RDB 快照实现快速恢复和持久化。

(参考这篇 《Redis系列2:数据持久化提高可用性》)

AOF(Append-Only File)作为Redis用于缓存持久化的一种方式,当你选择 "always" 作为 AOF 的写回策略时,这意味着每一个写操作都会被立即同步到磁盘中。

虽然这种策略可以最大限度地保证数据的安全性,但是它对性能的影响也是最大的,因为每次写操作都需要等待磁盘 I/O 完成。如果你的应用可以接受一点点数据丢失的风险,或者你的应用主要是读操作,你可能会想要调整 AOF 的写回策略以提高性能。

以下是几种可能的解决方案:

  1. 调整 AOF 写回策略:Redis 提供了几种 AOF 写回策略,包括 "always"(每个操作都立即写回)、"everysec"(每秒写回一次)、"no"(由操作系统决定何时写回)。如果你的应用可以接受一些数据丢失的风险,你可以尝试将 AOF 写回策略调整为 "everysec" 或 "no"。
  2. 使用 RDB 持久化:与 AOF 不同,RDB(Redis DataBase)持久化是通过生成数据快照来实现的。你可以配置 Redis 在指定的时间间隔内生成 RDB 快照,这种方式对性能的影响相对较小。
  3. 优化硬件:如果你的硬件(例如磁盘)性能较低,那么 I/O 操作可能会成为瓶颈。在这种情况下,你可能需要升级你的硬件。
  4. 使用缓存:如果你的应用主要是读操作,你可以考虑使用缓存来减轻数据库的负载。例如,你可以使用 Redis 的内存存储功能,或者使用其他的缓存系统。

注意,调整持久化策略或使用缓存都可能会增加数据丢失的风险,因此你需要根据你的应用需求和风险承受能力来选择合适的策略。

3.7 expires 淘汰过期数据

参考这篇文章《Redis系列18:过期数据的删除策略》,我们有详细的描述

Redis 有两种方式淘汰过期数据:

  • 惰性删除:当接收请求的时候发现 key 已经过期,才执行删除;
  • 定时删除:每 100 毫秒删除一些过期的 key。

定时任务的发起的频率由redis.conf配置文件中的hz来进行配置

# 代表每1s 运行 10次
hz 10

Redis 默认每 1 秒运行 10 次,也就是每 100 ms 执行一次,每次随机抽取一些设置了过期时间的 key(这边注意不是检查所有设置过期时间的key,而是随机抽取部分),检查是否过期,如果发现过期了就直接删除。

该定时任务的具体流程如下:

  • 定时serverCron方法去执行清理,执行频率根据redis.conf中的hz配置的值
  • 执行清理的时候,不是去扫描所有的key,而是去扫描所有设置了过期时间的key(redisDb.expires)
  • 如果每次去把所有过期的key都拿过来,那么假如过期的key很多,就会很慢,所以也不是一次性拿取所有的key
  • 根据hash桶的维度去扫描key,扫到20(可配)个key为止。假如第一个桶是15个key ,没有满足20,继续扫描第二个桶,第二个桶20个key,由于是以hash桶的维度扫描的,所以第二个扫到了就会全扫,总共扫描35个key
  • 找到扫描的key里面过期的key,并进行删除
  • 删除完检查过期的 key 超过 25%,继续执行4、5步

大家看最后一步,如果一致有超过25%的过期key,就会导致 Redis 一直去删除来释放内存,而删除是阻塞的。

所以,需要避免大量 key 过期早同一时期过期,这样可能需要重复删除多次才能降低到 25% 以下。

解决方案:

可以给缓存设置过期时间时加上一个随机值时间(在 EXPIREAT 和 EXPIRE 的过期时间参数上,加上一个一定大小范围内的随机数),使得每个key的过期时间分布开来,不会集中在同一时刻失效。

随机值我们团队的做法是:n * 3/4 + n * random() 。所以,比如你原本计划对一个缓存建立的过期时间为8小时,那就是6小时 + 0~2小时的随机值。

这样保证了均匀分布在 6~8小时之间。如图:

3.8 优化 bigkey

bigkey 是指含有较大数据或含有大量成员、列表数的 Key。以下是一些实际的例子:

  • 一个 STRING Key 的Value过大,比如超过 5MB
  • 一个 LIST 类型的 Key,它的List Size太大,比如10000 个
  • 一个 ZSET 类型的 Key,它的Member Size太大,比如 10000 个
  • 一个 HASH 格式的 Key,它的Member Size太大,比如 10000个,或者Value值总量过大,比如 100MB

bigkey 带来问题如下:

  1. OOM,或者达到 maxmemory 阈值导致请求阻塞或者key被驱逐。
  2. Redis Cluster 的数据负载最小粒度为 Key,这样如果某个node上有一个bigkey,就可能导致内存不均衡。
  3. bigkey 的读写都有有较大的带宽占用、内存占用,混合使用云主机情况下,会影响其他服务的资源存量。
  4. 删除一个 bigkey 造成主库较长时间的阻塞甚至引发同步中断或主从切换。

优化 Redis 的 bigkey 可以从以下几个方面入手:

  1. 拆分 bigkey:将一个含有大量成员、列表数或数据大小的 Key 拆分成多个小 Key,每个 Key 的成员数量或数据大小在合理范围内。这样可以避免单个 Key 占用过多内存,并且可以提高 Redis 的读写性能。
  2. 异步清理 bigkey:Redis 4.0 版本提供了 UNLINK 命令,可以用来安全地删除 bigkey,避免对 Redis 实例造成过大的负载。可以通过将 UNLINK 命令放在异步任务中执行,以避免对主线程造成阻塞。
  3. 使用更合适的数据结构:根据实际需求选择更合适的数据结构,比如使用哈希表(hash)代替字符串(string),使用有序集合(sorted set)代替列表(list)等。这样可以减少数据的内存占用,提高读写性能。
  4. 控制 key 的数量:尽量避免使用过多的 Key,尤其是在使用 Redis Cluster 时,过多的 Key 会导致数据分布不均,影响集群的性能和稳定性。
  5. 使用压缩功能:Redis 提供了压缩功能,可以将 bigkey 的数据进行压缩后再存储,减少内存占用和网络传输开销。但是需要注意的是,压缩和解压操作会增加 CPU 的负载,需要根据实际情况权衡利弊。
  6. 差异化过期时间:如果一批 key 的确是同时过期,可以在 EXPIREAT 和 EXPIRE 的过期时间参数上,加上一个一定大小范围内的随机数

3.9 其他原因

  • 复杂度过高的命令或查询全量数据。
  • 内存达到 maxmemory。
  • 客户端使用短连接和 Redis 相连。
  • Redis 实例的数据量大,导致生成 RDB 或 AOF 重写耗时严重。
  • Redis 实例运行机器的内存不足,导致 swap 发生,Redis 需要到 swap 分区读取数据。
  • 进程绑定 CPU 不合理。
  • Redis 实例运行机器上开启了透明内存大页机制。
  • 网卡压力过大。
  • Redis 实例之间以及内部数据传输阻塞,包括客户端、磁盘、主从通信、切片集群通信等问题。
  • 多 CPU 多核架构问题,包括绑核、绑 CPU 等。
  • sql 语句执行阻塞,包括慢查询、过期 key 等问题。

4 总结

优化步骤如下:

  • 获取 Redis 的基线延迟情况
  • 开启慢指令监控,定位慢指令导致的问题,分析并优化。
  • 开启慢请求日志,分析执行时间超时情况,以便分析和优化。
  • 解决常见的Redis慢执行问题
    • 网络通信延迟
    • 慢指令导致的延迟
    • Fork 生成 RDB 导致的延迟
    • AOF 文件系统或 RDB 大内存页问题,包括 AOF 持久化阻塞、大内存页等
    • 操作系统 Swap 操作问题,包括内存磁盘数据转换、内存清理等
    • 对swap导致的性能问题进行排查
    • AOF 的写回策略为 always,导致每个操作都要同步刷回磁盘
    • expires 淘汰过期数据
    • 优化 bigkey

Redis系列23:性能优化指南的更多相关文章

  1. 移动H5前端性能优化指南[转]

    移动H5前端性能优化指南 米随随2015.01.23 移动H5前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首 ...

  2. 移动H5前端性能优化指南

    移动H5前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网 ...

  3. web前端性能优化指南(转)

    web前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网络 ...

  4. 【转载】Spark性能优化指南——高级篇

    前言 数据倾斜调优 调优概述 数据倾斜发生时的现象 数据倾斜发生的原理 如何定位导致数据倾斜的代码 查看导致数据倾斜的key的数据分布情况 数据倾斜的解决方案 解决方案一:使用Hive ETL预处理数 ...

  5. 【转载】 Spark性能优化指南——基础篇

    转自:http://tech.meituan.com/spark-tuning-basic.html?from=timeline 前言 开发调优 调优概述 原则一:避免创建重复的RDD 原则二:尽可能 ...

  6. 【转】【技术博客】Spark性能优化指南——高级篇

    http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745207&idx=1&sn=3d70d59cede236e ...

  7. 【转】Spark性能优化指南——基础篇

    http://mp.weixin.qq.com/s?__biz=MjM5NDMwNjMzNA==&mid=2651805828&idx=1&sn=2f413828d1fdc6a ...

  8. 移动H5前端性能优化指南(转载)

    移动H5前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网 ...

  9. [推荐]移动H5前端性能优化指南

    [推荐]移动H5前端性能优化指南 http://isux.tencent.com/h5-performance.html

  10. jQuery性能优化指南(转载)

    现在jquery应用的越来越多, 有些同学在享受爽快淋漓coding时就将性能问题忽略了, 比如我. jquery虽在诸多的js类库中性能表现还算优秀, 但毕竟不是在用原生的javascript开发, ...

随机推荐

  1. 云原生时代崛起的编程语言Go远程调用gRPC实战

    @ 目录 概述 定义 背景 特点 四种服务方法 实战 环境配置 proto文件 简单RPC Token认证 服务器流式RPC 客户端流式RPC 双向流式RPC 概述 定义 gRPC 官网地址 http ...

  2. 2023-06-19:讲一讲Redis分布式锁的实现?

    2023-06-19:讲一讲Redis分布式锁的实现? 答案2023-06-19: Redis分布式锁最简单的实现 要实现分布式锁,确实需要使用具备互斥性的Redis操作.其中一种常用的方式是使用SE ...

  3. CSS3学习记录之loading动画

    loading动画就是在加载一些网页内容的时候呈现出来的小动画,记录一下学到的几种loading动画: 效果:http://39.105.101.122/myhtml/CSS/Loading/load ...

  4. CF1832F Zombies

    简要题意 给定 \(n\) 个左闭右开的区间 \(A_i = [L_i, R_i)\),其中 \(0\le L_i < R_i \le x\),你可以自由选择 \(k\) 个长度为 \(m\) ...

  5. 聊一聊Java中的Steam流

    1 引言 在我们的日常编程任务中,对于集合的制造和处理是必不可少的.当我们需要对于集合进行分组或查找的操作时,需要用迭代器对于集合进行操作,而当我们需要处理的数据量很大的时候,为了提高性能,就需要使用 ...

  6. 数据标注工具 Label-Studio

    文档抽取任务Label Studio使用指南 目录 1. 安装 2. 文档抽取任务标注 2.1 项目创建 2.2 数据上传 2.3 标签构建 2.4 任务标注 2.5 数据导出 2.6 数据转换 2. ...

  7. 2023郑州轻工业大学校赛邀请赛wh

    在这里,很感谢程立老师的帮助和选择我,我以后会跟着程老师,既然热爱,就要走下去! 2022年4月2号,我代表河南工业大学与郑州17所高校在郑州轻工业大学举办的"卓见杯"郑州轻工业大 ...

  8. Python中的弱引用与基础类型支持情况探究

    背景 最近有一个业务场景需要用Python自行实现一个简单的LRU cache,不可避免的接触到了弱引用这一概念,这里记录一下. 强引用 Python内存回收由垃圾回收器自动管理,当一个对象的引用计数 ...

  9. python打包方法

    在Python中,要编写setup.py文件,用于构建和打包你的Python项目,你可以遵循以下步骤: 创建项目目录结构:首先,你需要创建项目的目录结构,包括源代码文件.资源文件等.一个常见的项目结构 ...

  10. React函数式组件渲染、useEffect顺序总结

    参考资料: 深入React的生命周期(上):出生阶段(Mount) 深入React的生命周期(下):更新(Update) 精读<useEffect 完全指南> React组件重新渲染理解 ...