2024最新版Redis常见面试题包含详细讲解

Redis适用于哪些场景?

  1. 缓存
  2. 分布式锁
  3. 降级限流
  4. 消息队列
  5. 延迟消息队

说一说缓存穿透

缓存穿透的概念

用户频繁的发起恶意请求查询缓存中和数据库中都不存在的数据,查询积累到一定量级导致数据库压力过大甚至宕机。

缓存穿透的原因

比如正常情况下用户发起一个请求根据某个主键ID获取数据库信息,服务器接收到请求后会先查询缓存,如果缓存命中则返回,未命中就去查询数据库,数据库中存在则返回并存入Redis,不存在提示或者报错。
但是假如有人使用一定不存在的ID,比如负数或者很大的数值进行恶意频繁的请求,就会导致数据库的压力增大甚至宕机。

缓存穿透的解决方案:

  1. 在缓存中给不存在的ID设置null值。

对于那些缓存中和数据库中都查不到的数据,同样把它保存到缓存中并将value值设置为null,这样下次同样的id再来请求就直接从缓存中获取null值并返回。
优点:实现简单。
缺点:浪费内存,并且如果攻击者每次使用的是不同的脏数据进行攻击,这种方式是处理不了的。

  1. 使用布隆过滤器

使用布隆过滤器服务器的逻辑就会变成这样:

什么是布隆过滤器呢?
先来看下面这张图:
image.png
布隆过滤器的底层是一个bitmap,也就是一个数组,每个下标只存储0或1,默认初始化时全部都为0。可以在其中定义多个不同的哈希函数对要存储的数据进行计算,不同的哈希函数计算出的结果作为数组的下标将其对应的值改为1。这样不管是存数据还是查询数据都可以通过哈希计算得到对应下标然后根据是否为1判断是否存在,如果有一个值不为1则就是不存在。
但是,这种机制也是会出现一定的误判率的,具体看下面这张图:
image.png
首先将id1和id2存入布隆过滤器中,得到了对应的下标并设置为1,这个时候id3也要存进来,然后通过哈希计算得到了3、9、12的下标,这个时候虽然id3并不存在,但是布隆过滤器也会判定为存在!这个就是误判。

说一说缓存击穿

缓存击穿的概念

在Redis缓存中某条热点数据过期了,然后在这一时间有大量的并发请求到服务器导致缓存中查不到,就都请求到了数据库,数据库压力瞬间增大甚至宕机。

缓存击穿的原因

缓存穿透的概念基本就是它的出现的原因,理论上当在数据库查到数据时会将数据放到缓存,后续请求就可以从缓存中获取到,但是缓存穿透发生的节点就是在数据库查到数据之后和将数据放回缓存之前这一时间段。

缓存击穿的解决办法

  1. 使用逻辑过期时间

逻辑过期时间类似于Mybatis的逻辑删除,可以对缓存中的数据增加一个expire属性,对应的值就是过期时间。这样当请求过来之后,从缓存中获取到数据判断是否逻辑过期了,如果逻辑过期了就创建一个线程进行缓存重建,注意,这里需要加上互斥锁进行,新开线程是为了不阻塞主线程,而加互斥锁是防止后续的线程也进行缓存重建流程,在缓存重建完成之前主线程都就会直接返回这条过期数据给用户。
**缓存重建:**查询数据库,并重新放入缓存并设置新的逻辑过期时间。
优点:可以保证高可用性。
缺点:在过期重建期间,返回的数据是已经过期的,不能保证数据的完全一致性。

  1. 互斥锁

当缓存中查询不到该数据时,先获取互斥锁(可以利用redis分布式锁),然后再去查询数据库并将数据重新放入缓存和设置过期时间,最后释放锁。
优点:保证数据的完全一致性。
缺点:性能差,加锁后其它线程只能等待。
下面是两种方式的图解对比:
image.png

说一说缓存雪崩

缓存雪崩的概念

大量的热点数据在同一时间段缓存过期或Redis宕机了,导致大量请求到达数据库,带来巨大压力。

缓存雪崩的原因

缓存雪崩的主要原因有两种,一种是大量的key都设置了同一过期时间,如果在数据过期是出现大量的请求就会导致数据库压力过大;另一种是Redis直接宕机了,那么所有的请求到会直接到达数据;

缓存雪崩的解决办法

  1. 设置随机值

在给不同的key设置过期时间的时候,可以设置一个随机值比如1-5分钟时间,让过期时间加上这个随机值作为key的过期时间,这样就避免了在同一时间大量的key同时过期。

  1. 利用Redis集群提高可用性
  2. 给缓存业务添加降级限流策略
  3. 给业务添加多级缓存

Redis 如何实现双写一致

什么是双写一致?按照正常逻辑读数据时会先查询缓存,如果缓存未命中才会去查数据库;写数据时则需要数据库的数据和缓存中的数据保持一致。正常情况下我们先删除缓存,再更新数据库并重新放回缓存是没有任何问题的。但是在分布式场景下或者并发场景下,这种方式就会导致在写数据时的数据不一致问题。
比如下面的两种情况都会导致数据不一致性问题:
image.png
而保证写数据时数据库和缓存中的数据保持完全一致,也就是所说的双写一致。

缓存双删

既然先删缓存再写数据库和先写数据库再删缓存都不行,那我们就删两次,在写数据库之前删一次缓存,写完之后再删一次;这种方式基本上可以解决问题,但是写完之后我们不能立马删除缓存,而是需要延迟一会儿再删除,为什么呢?因为大部分公司数据库都采用了主从的模式,那么刚更新数据库后需要同步给从数据库,这个时间点如果立马删除缓存数据可能还是会导致数据不一致性(一般主数据库接收写操作,从数据库接收读操作),所以要延迟一会儿再进行删除。
但是因为这个延迟时间并不好控制,所以延迟双删在存在数据库主从模式的架构下是不建议使用的,它不能保证数据库的完全一致性。

读写锁

首先先来看下具体的实现思路:
image.png 可以利用读写锁的方式,在写数据的时候我们加上排他锁,也就是写数据时其他线程是不可以进行读和写操作的。而在读数据时是加上共享锁,使得其他线程可以并发读取数据。
读写锁的方式既保证了数据的强一致性,又保证了效率。那么具体实现方式可以使用Redisson来实现。
读锁代码:
image.png
写锁代码:
image.png

异步通知

具体实现思路如下图:image.png
首先需要加一个中间层,也就是MQ;在进行数据库写的操作时需要将这条消息发送到MQ中,然后再写一个监听这条消息的方法,去进行缓存的更新操作。那么这样就可以保证更新完数据以后缓存也会实时的进行更新,而可靠性也就相当于交给了MQ了。
优点:保证了数据最终一致性,并且不影响效率。
缺点:在同步MQ和MQ进行更新操作期间,用户读到的数据不是最新的。

Redis 如何实现持久化?

Redis实现持久化的方式有两种,一种是RDB的形式,一种是AOF的形式,一般公司项目中都会使用两种方式结合的形式保证数据的持久化。
什么是持久化?持久化其实说白了就是将数据写到磁盘中,因为Redis是基于内存的,所以数据都是放在内存中,如果Redis崩溃了,那么就会导致所有的数据丢失,这是一个严重的问题!
为了解决这种问题,就可以将内存中的数据写入到磁盘中,一旦Redis崩溃了,那我们还可以在重启Redis时将磁盘中保存好的数据进行回复,而这种操作就被称为持久化。
那么接下来我们需要思考下面几个问题:

  1. 在什么节点去进行持久化的操作?
  2. 怎么保证持久化的数据和Redis崩溃前的数据保持完全一致?

RDB

RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照,简单来说就是把内存中的所有数据都记录到磁盘中,默认会创建一个名为 dump.rdb 的文件保存数据,当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
在Redis配置文件中可以通过 dbfilename 属性查看RDB的文件名:
image.png
Redis的RDB持久化操作可以在以下两种情况下触发:

  1. 手动触发:
    • save 命令:这是手动触发RDB持久化的机制。当执行 save 命令时,Redis会阻塞主线程,创建一个子进程,并将数据快照保存到磁盘上的RDB文件中。在持久化完成之前,Redis的主线程将无法处理其他请求。因此,如果Redis中的数据量较大,使用 save 命令可能会造成长时间的阻塞,因此在线上环境中通常不推荐使用此命令。
    • bgsave 命令:这是异步触发RDB持久化的机制。当执行 bgsave 命令时,Redis会fork一个子进程来负责持久化操作,而主进程可以继续处理其他请求。因此,使用 bgsave 命令可以避免阻塞主线程,提高Redis的性能。
  2. 自动触发:
    • 自动触发RDB持久化的机制,这可以通过在配置文件中设置 save 指令来实现。例如,设置 save 900 1 表示在900秒(15分钟)内,如果至少有1个键发生变化,则自动触发RDB持久化操作。这样可以根据实际需求来灵活地控制RDB持久化的频率。

需要注意的是,在自动触发RDB持久化时,Redis也会选择 bgsave 而不是 save 来进行持久化操作,以避免阻塞主线程。
打开本地的Redis配置文件,可以看到Redis有下面默认配置:
image.png
这里有三个save参数:

  1. 如果在900秒内,至少有1个键发生变化,就执行一次RDB持久化操作。
  2. 如果在300秒内,至少有10个键发生变化,也执行一次RDB持久化操作。
  3. 如果在60秒内,至少有10000个键发生变化,还会执行一次RDB持久化操作。

当设置了多个save参数时,Redis会按照从上到下的顺序依次检查每个save参数的条件是否满足。如果某个save参数的条件被满足(即时间间隔内数据的变化量达到了指定的数量),Redis就会执行一次RDB持久化操作。这意味着,只要有一个save参数的条件被满足,Redis就会进行持久化操作。

  1. 优点:
    1. 以二进制压缩文件的形式存储,占用内存更小,恢复时更快。
  2. 缺点:
    1. 周期性数据丢失,如果在Redis宕机之前的最后一次进行RDB持久化后,仍有别的写操作执行,那么这部分数据会导致丢失。

AOF

  1. AOP的概念与原理

AOP,即Append Only File,是Redis的一种持久化方式。与RDB(Redis Database)快照模式不同,AOP模式是通过记录每一条修改数据的命令,并将这些命令追加到AOF文件中来实现数据的持久化。当Redis服务器重启时,它会通过重新执行AOF文件中的命令来恢复数据。
AOP模式的核心原理是“先执行命令,后写日志”。每当Redis执行一个修改数据的命令时,它都会将该命令写入AOF文件。这种方式的优点是可以确保数据的实时性和准确性,因为即使在系统崩溃的情况下,也不会丢失任何已经写入AOF文件的命令。

  1. **AOP的配置与使用
    **在Redis中,AOP模式默认是关闭的,需要通过修改配置文件来启用。在Redis的配置文件(redis.conf)中,可以通过设置以下参数来启用AOP模式:
    1. appendonly yes:启用AOP模式。
    2. appendfilename “appendonly.aof”:设置AOF文件的名称,默认为"appendonly.aof"。
    3. appendfsync always|everysec|no:设置AOF文件的写入策略。其中,"always"表示每次写入操作都同步到AOF文件;"everysec"表示每秒同步一次;"no"表示由操作系统控制同步周期。
  2. **AOP的优点与不足
    **AOP模式具有以下优点:
    1. 数据实时性和准确性高:由于AOP模式记录了每一条修改数据的命令,因此可以确保数据的实时性和准确性。
    2. 可读性强:AOF文件以文本形式存储,可读性强,便于进行故障排查和数据恢复。
    3. 支持增量备份:AOP模式支持增量备份,只需要备份自上次备份以来的AOF文件即可。

然而,AOP模式也存在一些不足之处:

  1. 文件体积大:随着命令的不断写入,AOF文件的体积会越来越大,占用更多的磁盘空间。
  2. 恢复速度慢:当系统崩溃时,Redis需要重新执行AOF文件中的每一条命令来恢复数据,这可能会花费较长的时间。
  3. AOP重写机制

为了解决AOF文件体积过大的问题,Redis引入了AOP重写机制。AOP重写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。在重写过程中,Redis会遍历当前内存中的所有数据,并生成相应的写命令,然后将这些命令写入新的AOF文件中。重写后的AOF文件体积会大大减小,但需要注意的是,在重写过程中,Redis的写操作可能会受到一定的影响。

混合持久化

重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。 

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。 将 rdb 文 件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自 持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可 以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。

Redis 的过期策略

惰性过期

  • 描述:当客户端尝试访问一个key时,Redis会检查这个key是否设置了过期时间,并且是否已过期。如果key已经过期,Redis会立即删除这个key,并且不会返回任何数据给客户端。
  • 优点:节省CPU资源,因为过期检查只在key被访问时执行。
  • **缺点:**如果过期key长时间不被访问,它们会持续占用内存空间。

定时过期

  • 描述: Redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定时遍历这个字典来删除到期的 key。
  • **定时扫描策略(不能手动设置):**Redis 默认会每秒进行十次过期扫描,过期扫描不会遍历过期字典中所有的 key,而是 采用了一种简单的贪心策略。

1、从过期字典中随机 20 个 key;
2、删除这 20 个 key 中已经过期的 key;
3、如果过期的 key 比率超过 1/4,那就重复步骤 1;
同时,为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认上述操作不会超过 25ms。

  • **优点:**确保过期key得到及时删除,避免内存空间的浪费,并减少数据不一致的风险。
  • **缺点:**需要消耗一定的CPU资源来执行过期检查,并且可能存在延迟删除的情况,即key的过期时间和实际删除时间之间存在一定的时间差。

Redis实际使用的过期策略

  • Redis结合了惰性过期和定时过期两种策略。当客户端访问key时,Redis会执行惰性过期检查;同时,后台任务也会周期性地执行定时过期检查,以确保过期key得到及时删除。
  • 这种组合策略既能够节省CPU资源,又能够保持内存空间的清洁和数据的一致性。

Redis 的淘汰策略

Redis的淘汰策略(Eviction Policy)定义了当Redis内存使用达到其最大限制(由maxmemory配置指令设置)时,Redis应该如何处理新的写请求(如SET、LPUSH等)。以下是Redis的八种淘汰策略的详细说明:

  1. noeviction(默认策略):当内存不足以容纳新写入数据时,它不会淘汰任何数据,而是直接返回错误给写请求的客户端。
  2. allkeys-random:当内存不足以容纳新写入数据时,它会从所有key中随机选择并删除一些key。
  3. volatile-random:当内存不足以容纳新写入数据时,它只会从设置了过期时间的key中随机选择并删除一些key。
  4. **volatile-ttl:**当内存不足以容纳新写入数据时,它会在设置了过期时间的key中,挑选那些快要过期的key进行删除。
  5. allkeys-lru(Least Recently Used):当内存不足以容纳新写入数据时,它会从所有key中选择最久未使用的key进行删除。
  6. **volatile-lru:**与allkeys-lru类似,但是只会从设置了过期时间的key中选择最久未使用的key进行删除。
  7. allkeys-lfu(Least Frequently Used):当内存不足以容纳新写入数据时,它会从所有key中选择最不经常使用的key进行删除。LFU是一个基于访问频率的淘汰策略。
  8. **volatile-lfu:**与allkeys-lfu类似,但是只会从设置了过期时间的key中选择最不经常使用的key进行删除。

volatile-xxx 策略只会针对带过期时间的 key 进行淘汰,allkeys-xxx 策略会对所有的 key 进行淘汰。如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时 不必携带过期时间。如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被 LRU 算法淘汰。

LRU 算法原理

Redis 为实现近似 LRU 算法,它给每个 key 增加了一个额外的小字段,这个字段的长度是 24 个 bit,也就是最后一次被访问的时间戳。 

上面提到处理 key 过期方式分为定时集中处理和懒惰处理,LRU 淘汰不一样,它的处理 方式只有懒惰处理。当 Redis 执行写操作时,发现内存超出 maxmemory,就会执行一次 LRU 淘汰算法。这个算法也很简单,就是随机采样出 5(可以配置) 个 key,然后淘汰掉最旧的 key,如果淘汰后内存还是超出 maxmemory,那就继续随机采样淘汰,直到内存低于 maxmemory 为止。
如何采样就是看 maxmemory-policy 的配置,如果是 allkeys 就是从所有的 key 字典中 随机,如果是 volatile 就从带过期时间的 key 字典中随机。每次采样多少个 key 看的是 maxmemory-samples 的配置,默认为 5。
同时 Redis3.0 在算法中增加了淘汰池,进一步提升了近似 LRU 算法的效果。 淘汰池是一个数组,它的大小是 maxmemory_samples,在每一次淘汰循环中,新随机出 来的 key 列表会和淘汰池中的 key 列表进行融合,淘汰掉最旧的一个 key 之后,保留剩余较旧的 key 列表放入淘汰池中留待下一个循环 。
lru 和 lfu 的区别:

  • lru 算法:lru主要基于最近最少访问进行删除,比如key1总访问次数是9,key2的总访问次数是4,那么key2将会被删除。
  • lfu 算法:lfu主要基于访问频率进行删除,比如key1总访问次数是9,但是十分钟内key1的访问次数是2,key2的总访问次数是4,但是十分钟内key2的访问次数是4,那么key1将会被删除。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生命在于学习——Python人工智能原理(3.1.2)

一、概率基本知识 1.3 常见概型 1.3.1 古典概型 定义1 古典概型 若随机事件E满足如下两个条件: (1)样本空间S中只有有限个样本点。 (2)样本空间S中每个样本点发生都是等可能的。 这样的随机试验称为古典概型。 P(A)…

暑期大数据人工智能学习-企业项目试岗实训开营

暑期企业项目-试岗实训活动全面开启啦 跟张良均老师学大数据人工智能 不仅可以提供实习证明,有需要话也可以提供实习鉴定报告 √54个热门案例拆解 √40项目实战课程 √27个项目可选 √4个项目方向

企业本地大模型用Ollama+Open WebUI+Stable Diffusion可视化问答及画图

最近在尝试搭建公司内部用户的大模型,可视化回答,并让它能画图出来, 主要包括四块: Ollama 管理和下载各个模型的工具Open WebUI 友好的对话界面Stable Diffusion 绘图工具Docker 部署在容器里,提高效率 以上运行环境…

to_json 出现乱码的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

基于MIMO系统的预编码matlab性能仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 最小均方误差(MMSE)准则 4.2 量化准则 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 …

让围绕数据库构建大模型应用更简单方便--DB-GPT

DB-GPT的目的是构建大模型领域的基础设施,通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Multi-Agents框架协作、AWEL(智能体工作流编排)等多种技术能力,让围绕数据库构建大模型应用更简单,更方便。 1 处理流程 DB-GPT系…

使用supportFragmentManager管理多个fragment切换

android studio创建的项目就没有一个简单点的框架,生成的代码都是繁琐而复杂,并且不实用。 国内的页面一般都是TAB页面的比较多,老外更喜欢侧边菜单。 如果我们使用一个activity来创建程序,来用占位符管理多个fragment切换&…

网络连接之队头阻塞!!!

一、什么是队头阻塞 队头阻塞,在网络模型中简单理解就是,对于队列型的请求模型,如HTTP的请求-响应模型、TCP的ACK确认机制,都依赖得到一个具体的响应包,如果收不到这个响应包,那下一个请求就不能发&#x…

如何高效安全的开展HPC数据传输,保护数据安全?

高性能计算(HPC)在多个行业和领域中都有广泛的应用,像科学研究机构、芯片IC设计企业、金融、生物制药、能源、航天航空等。HPC(高性能计算)环境中的数据传输是一个关键环节,它涉及到将数据快速、安全地在不…

hive的表操作

常用的hive命令 切换数据库use test;查询表的建表信息show create table 数据库名称.表名;查看表的类型信息desc formatted 数据库名称.表名; 删除内部表 drop table 数据库名称.表名; 先启动hdfs ,mysql , hiveservice2,beeline CREATE [EX…

Jenkins 创建流水线任务

Jenkins是一个流行的持续集成(Continuous Integration,CI)工具。 Jenkins 创建任务 选择“流水线”类型,该类型的优点是定制化程度非常高 (可选)添加“参数化构建” 配置仓库选项(ssh连接、分支)和凭据…

vue 中使用element-ui实现锚点定位表单

效果图&#xff1a; 代码&#xff1a; html代码&#xff1a; <div class"content-left"><el-tabs :tab-position"left" tab-click"goAnchor"><el-tab-pane v-for"(item,index) in anchorNameList"v-anchor-scroll:ke…

《C++20设计模式》适配器模式经验分享

文章目录 一、前言二、对于接口的讨论三、实现1、对象适配器1.1 UML类图1.2 实现 2、类适配器 四、最后 一、前言 从适配器模式开始就是类的组合聚合&#xff0c;类与类之间结构性的问题了。 适配器模式解决的问题&#xff1a; 适配器模式能够在不破坏现有系统结构的情况下&a…

问题集锦1

01.inner中使用JwtTokenUtil.getUserCode() 前端调用上传&#xff08;java&#xff09;&#xff0c;上传使用加购 Overridepublic Boolean insertShoppingCart(InsertShoppingCartParamsDto dto) {// 通过userCode,itemCode和supplierCode来判断当前加购人添加到购物车的商品是…

前端FCP指标优化

优化前 第三方依赖按需引入之后&#xff0c;打包的总体积减小到初始值的55%&#xff0c;但是依然存在很大的js文件&#xff0c;需要继续优化 chunk-vendors.js进行分包之后 截图 compression-webpack-plugin压缩之后 截图

使用Nginx反向代理KKFileView遇到问题

使用KKFileView 4.0 以上版本 在KKFileView官网上&#xff0c;关于使用Nginx代理&#xff0c;建议配置如下 一、修改Nacos 在Nginx的conf文件夹中修改 nginx.conf ,新加 红框内的IP地址为代理服务器地址&#xff08;即安装KKFileView的服务器地址&#xff09; 二、修改KKFil…

【Dison夏令营 Day 07】用 Python 和 Rich 制作 Wordle克隆(下篇)

在大流行期间&#xff0c;Wordle 在 Twitter 上还算比较流行的一款基于网络的益智游戏&#xff0c;要求玩家每天在六次或更短时间内猜出一个新的五个字母的单词&#xff0c;每个人得到的单词都是一样的。 在本教程中&#xff0c;你将在终端上创建自己的 Wordle 克隆。自 2021 …

ViewBinding的使用(因为kotlin-android-extensions插件的淘汰)

书籍&#xff1a; 《第一行代码 Android》第三版 开发环境&#xff1a; Android Studio Jellyfish | 2023.3.1 问题&#xff1a; 3.2.4在Activity中使用Toast章节中使用到了kotlin-android-extensions插件,但是该插件已经淘汰,根据网上了解,目前使用了新的技术VewBinding替…

three.js地理坐标系有哪些,和屏幕坐标系的转换。

坐标系很好理解&#xff0c;就是点线面体的位置&#xff0c;一个点是一个坐标&#xff0c;一条线段2个坐标&#xff0c;一个矩形四个坐标&#xff0c;一个立方体8个坐标&#xff0c;three.js面对的是三维空间&#xff0c;屏幕则是二维的&#xff0c;这就面临着转换问题&#xf…

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《面向电网调峰的电动汽车聚合商多层级实时控制策略》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…