性能优化 - 案例篇:缓存_Guava#LoadingCache设计

article/2025/7/27 22:20:31

文章目录

  • Pre
  • 引言
  • 1. 缓存基本概念
  • 2. Guava 的 LoadingCache
    • 2.1 引入依赖与初始化
    • 2.2 手动 put 与自动加载(CacheLoader)
      • 2.2.1 示例代码
    • 2.3 缓存移除与监听(invalidate + removalListener)
  • 3. 缓存回收策略
    • 3.1 基于容量的回收(LRU)
    • 3.2 基于时间的回收
    • 3.3 基于 JVM GC 的回收
      • 3.3.1 GC 回收引发的缓存颠簸问题
  • 4. 常见缓存算法简介
    • 4.1 FIFO(先进先出)
    • 4.2 LRU(最近最少使用)
    • 4.3 LFU(最近最不常用)
  • 5. 简易 LRU 实现——LinkedHashMap
    • 5.1 功能局限与线程安全
  • 6. 操作系统层面的预读与文件缓存
  • 7. 缓存优化的一般思路
  • 8. 缓存应用案例
  • 9. 小结

在这里插入图片描述


Pre

性能优化 - 理论篇:常见指标及切入点

性能优化 - 理论篇:性能优化的七类技术手段

性能优化 - 理论篇:CPU、内存、I/O诊断手段

性能优化 - 工具篇:常用的性能测试工具

性能优化 - 工具篇:基准测试 JMH

性能优化 - 案例篇:缓冲区


  1. 引言:解释缓存与缓冲的区别及缓存在性能优化中的重要性;
  2. 缓存基本概念:缓存的本质、应用场景、进程内 vs 进程外缓存;
  3. Guava LoadingCache(LC)示例:
    3.1 引入依赖与初始化配置;
    3.2 手动 put 与自动加载(CacheLoader)模式;
    3.3 缓存容量、初始大小与并发级别设置;
    3.4 缓存移除与监听(invalidate + removalListener);
  4. 缓存回收策略:
    4.1 基于容量的回收(LRU);
    4.2 基于时间的回收(expireAfterWrite / expireAfterAccess);
    4.3 基于 JVM GC 的回收(weakKeys / weakValues / softValues);
    4.4 GC 回收引发的缓存颠簸问题与解决思路;
  5. 缓存算法简述:FIFO、LRU、LFU 三种常见策略;
  6. 用 LinkedHashMap 实现简易 LRU:
    6.1 LinkedHashMap 构造参数与访问顺序;
    6.2 覆盖 removeEldestEntry 实现容量控制;
    6.3 线程安全与功能局限性说明;
  7. 操作系统层面的预读与文件缓存:readahead 机制、完全加载策略;
  8. 缓存优化一般思路:何时用缓存、容量与命中率考量;
  9. 缓存的一些注意事项与示例:HTTP 304、CDN;

引言

在性能优化 - 案例篇:缓冲区中,介绍了“缓冲”这一优化手段——通过将数据暂存到内存缓冲区,批量顺序读写来缓解设备间的速度差异。与缓冲相伴随的“孪生兄弟”就是缓存(Cache)。缓存将常用数据放到相对高速的存储层(如内存)中,从而在后续访问时实现瞬时读取,显著提升性能。

举例而言:

  • 浏览热门页面时,只要缓存中已有渲染结果,就可以实现“秒开”;
  • 对数据库而言,引入缓存后,频繁查询热点记录可以直接命中缓存,数据库几乎无需负载。

缓存几乎是软件中最常见的优化技术。从 CPU L1/L2/L3 缓存到 Redis、Memcached 这样的分布式缓存,无不围绕“速度差异协调”这一核心展开。

接下来我们主要聚焦于进程内缓存——堆内缓存,以 Guava 的 LoadingCache 为示例讲解堆内缓存设计思路、常见回收策略和算法实现。


1. 缓存基本概念

缓存的核心作用,是在两个速度差异巨大的组件之间增加一层高速存储:

  • 速度慢组件:如数据库、文件存储,访问一次可能耗费几毫秒或更长;
  • 速度快组件:如 CPU 寄存器、内存读写,只需几十纳秒;
  • 缓存层(中间层):通常部署在内存中,通过哈希映射、LRU 回收等策略,只要缓存命中就能以几百纳秒返回结果。

根据缓存所在的物理位置,可将其分为:

  1. 进程内缓存(堆内缓存):直接存放在 JVM 堆里,访问速度最快,但容量受限于可用堆内存;
  2. 进程外缓存(进程间或分布式缓存):如 Redis、Memcached,通常运行在独立进程或集群里,通过网络访问,虽然速度比数据库快许多,但仍比堆内缓存慢一个数量级;

接下来重点讲解 进程内缓存,常见实现包括 Guava Cache、Caffeine、Ehcache、JCache 等。它们都提供了基于内存分片、高并发访问、灵活回收策略和统计监控的堆内缓存解决方案。

在这里插入图片描述


2. Guava 的 LoadingCache

在这里插入图片描述

Guava 提供了功能强大的 Cache 接口和 LoadingCache 实现,既支持手动存入(put()),也支持在缓存未命中时“自动加载”(CacheLoader)。下面通过示例逐步介绍其用法与内部配置要点。

2.1 引入依赖与初始化

首先,通过 Maven 将 Guava 库加入项目:

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>29.0-jre</version>
</dependency>

然后,使用 CacheBuilder 来创建一个 LoadingCache

LoadingCache<String, String> lc = CacheBuilder.newBuilder()// 设置最大缓存容量:达到上限后回收其他元素.maximumSize(1000)// 设置初始容量:底层 Hash 表的初始大小为 16(默认).initialCapacity(16)// 设置并发级别:将缓存分片成 4 个 segment,提升并发读写性能.concurrencyLevel(4).build(new CacheLoader<String, String>() {@Overridepublic String load(String key) throws Exception {// 缓存未命中时,自动调用 slowMethod 从外部数据源加载return slowMethod(key);}});
  • maximumSize(int):指定 缓存中可保留条目的最大数量,一旦超过,将根据回收策略(默认 LRU)移除旧元素;
  • initialCapacity(int):指定底层哈希表初始大小(bucket 数量),避免在缓存初始化时反复扩容;
  • concurrencyLevel(int):指定并发写的“分段”数,Guava 会将内部数据结构拆分为 concurrencyLevel 个部分,以减少并发冲突;

2.2 手动 put 与自动加载(CacheLoader)

LoadingCache 支持两种获取方式:

  1. 手动 put()

    lc.put("key1", "value1");
    String v = lc.getIfPresent("key1");  // 立即返回 "value1"
    

    在这种模式下,开发者负责将外部数据同步写入缓存。

  2. 自动加载 get()

在这里插入图片描述

// 第一次调用:缓存中无 key "a",触发 CacheLoader.load("a")
long start = System.nanoTime();
String result1 = lc.get("a");   // slowMethod("a") 需 1s
System.out.println("第一次调用耗时: " + (System.nanoTime() - start));
// 第二次调用:缓存命中,迅速返回
long start2 = System.nanoTime();
String result2 = lc.get("a");
System.out.println("第二次调用耗时: " + (System.nanoTime() - start2));

其中 load(String key) 方法可同步加载所需数据(如从数据库或外部 API 拉取),并在返回值后自动存入缓存。

2.2.1 示例代码

public class GuavaCacheDemo {// 模拟一个缓慢方法:睡眠 1 秒后返回结果static String slowMethod(String key) throws Exception {Thread.sleep(1000);return key + ".result";}public static void main(String[] args) throws Exception {LoadingCache<String, String> lc = CacheBuilder.newBuilder().maximumSize(1000).initialCapacity(16).concurrencyLevel(4).recordStats()   // 开启统计信息收集.build(new CacheLoader<String, String>() {@Overridepublic String load(String key) throws Exception {return slowMethod(key);}});// 第一次 get,会调用 slowMethodlong t1 = System.nanoTime();String v1 = lc.get("a");long elapsed1 = System.nanoTime() - t1;System.out.println("第一次 get 用时: " + elapsed1 + " ns");// 第二次 get,立即返回long t2 = System.nanoTime();String v2 = lc.get("a");long elapsed2 = System.nanoTime() - t2;System.out.println("第二次 get 用时: " + elapsed2 + " ns");// 输出命中率与加载次数等统计System.out.println("Cache Stats: " + lc.stats());}
}
  • recordStats():开启缓存统计功能,可用于后续分析 hitRate()loadSuccessCount() 等指标;
  • CacheLoader.load():当 key 未命中时,自动调用并将结果写回缓存;

2.3 缓存移除与监听(invalidate + removalListener)

  • 手动删除

    lc.invalidate("a");  // 移除 key "a" 对应的缓存项
    
  • 监听删除事件

    LoadingCache<String, String> lc2 = CacheBuilder.newBuilder().removalListener(notification -> {System.out.println("移除: " + notification.getKey() + " 因为 " + notification.getCause());}).maximumSize(100).build(new CacheLoader<>() {@Overridepublic String load(String key) { return slowMethod(key); }});
    

    当缓存项因为容量、过期、显式 invalidate() 等原因被移除时,监听器会收到回调,可用于日志、监控或二次清理。


3. 缓存回收策略

在缓存容量有限的前提下,需设计合适的回收策略来剔除“冷”或不再需要的数据,以保证“热点”数据得到优先保留。Guava 原生支持多种回收方式:

3.1 基于容量的回收(LRU)

  • maximumSize(long):当超过指定数量时,按照“最近最少使用(LRU)”策略移除最旧项;
  • LRU 意味着:每次缓存命中(get())或写入(put())时,该条目被标记为“最近被使用”;容量满时,优先移除最久未被访问的条目;
  • 这是默认的回收策略,适合大多数“热点覆盖度有限”的场景。

3.2 基于时间的回收

  • expireAfterWrite(long duration, TimeUnit unit):在缓存项被写入后,若在 duration 时间内未被访问,自动过期移除;
  • expireAfterAccess(long duration, TimeUnit unit):在缓存项最后一次访问后,若超过 duration,自动过期移除;
  • 这两种策略可以组合使用,用于场景如“用户会话缓存”、“短期热点数据”。

3.3 基于 JVM GC 的回收

  • Guava 提供了 weakKeys(), weakValues(), softValues() 等方法,利用不同强度的引用进行回收:

    • weakKeys():将缓存 key 按弱引用存放,若 key 对象仅被缓存引用,则可随时被 GC 回收,相应条目自动失效;
    • weakValues():将缓存 value 按弱引用存放,若 value 对象不再被强引用,则可被 GC 回收;
    • softValues():将 value 以软引用存放,当 JVM 内存不足时,GC 会优先回收这些软引用对象;
  • 典型语法:

    Cache<String, byte[]> cache = CacheBuilder.newBuilder().maximumSize(1000).weakValues().build();
    
  • 面试高频:若同时设置 weakKeys()weakValues(),则当 key 或 value 都失去任何强引用后,该条目会被 GC 回收。

3.3.1 GC 回收引发的缓存颠簸问题

当缓存条目使用弱引用或软引用,一旦 JVM 触发 GC,就可能一次性清空大批缓存数据。若该缓存频繁被访问,缓存将被迅速重新加载,导致连续触发多次 GC 和缓存“哗啦啦回补”的现象——CPU 消耗骤增,却无法留住数据。

解决思路

  • 仅对内存占用较大的非热点对象使用 softValues(),而不是对所有缓存。一旦发现缓存颠簸,可考虑放宽 GC 压力或降低缓存容量;
  • 尽量使用基于容量+时间的回收,避免过度依赖 JVM GC;
  • 在缓存加载逻辑中加入适当延迟,防止短时间内同一批 key 被重复加载。

4. 常见缓存算法简介

在这里插入图片描述

除了 Guava 提供的默认 LRU,缓存领域常见还有两种算法:

4.1 FIFO(先进先出)

  • 按“插入顺序”回收:

    • 缓存满时,移除最早插入的条目;
    • 结构简单,但不考虑条目热度;
    • 适用于“日志队列”、“任务处理队列”这类只关心先来先服务的场景。

4.2 LRU(最近最少使用)

  • 按“访问顺序”回收:

    • 每次 get()put() 时,将条目移至最近位置;
    • 满载时移除最久未被访问的条目;
    • 适用于“热点数据需长时间保留”的场景,是一般缓存中最为常见的策略。

4.3 LFU(最近最不常用)

  • 按“访问频率”回收:

    • 维护每个条目的访问计数;
    • 缓存满时,移除访问计数最少的条目;若存在多项访问计数相同,则移除“最久未使用”者;
    • 适用于需要保留“高访问频次”数据的场景,但实现较复杂,需要额外维护计数与优先级队列。

5. 简易 LRU 实现——LinkedHashMap

在 Java 中,要实现一个轻量级的 LRU 缓存,最便捷的方式是利用 LinkedHashMap 提供的“访问顺序”功能:

public class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int capacity;public LRUCache(int capacity) {// 初始容量 16,负载因子 0.75,accessOrder=true 表示按访问顺序排列super(16, 0.75f, true);this.capacity = capacity;}// 当 put 后,自动调用此方法判断是否需要移除最老条目@Overrideprotected boolean removeEldestEntry(Map.Entry<K, V> eldest) {return size() > capacity;}
}
  • 构造参数说明

    • initialCapacity:初始哈希表桶数,默认 16;
    • loadFactor:负载因子(0.75f);
    • accessOrder=true:按照“访问顺序”保持双向链表;
  • removeEldestEntry:在每次 put() 后自动调用,若返回 true,则移除“最久未访问”者,即 LRU 算法的核心。

在这里插入图片描述

5.1 功能局限与线程安全

  • 优势:代码简洁,无需自行维护优先级队列或计数器;

  • 局限

    1. 仅基于“条目数量”控制容量,不能指定基于“内存占用大小”回收;
    2. 无法设置“基于时间过期”或“基于访问次数”回收;
  • 线程安全LinkedHashMap 本身并非线程安全,如需并发访问,应加锁或改用 ConcurrentLinkedHashMap / Guava Cache / Caffeine。


6. 操作系统层面的预读与文件缓存

在这里插入图片描述

在操作系统层面,对文件 I/O 缓存设计也非常智能,进一步支撑了高性能缓存架构。Linux 下可以通过 free 命令查看内存状态,其中 cached 区域往往十分庞大:

$ free -htotal        used        free      shared  buff/cache   available
Mem:           16Gi       4.2Gi       2.5Gi       128Mi       9.4Gi       11Gi
Swap:         2.0Gi       512Mi       1.5Gi
  • buff/cache:表示操作系统将磁盘块缓存在内存中的容量,包括文件系统页缓存、目录缓存等;
  • Readahead(预读):当进程顺序读取文件时,内核会自动尝试以“页面”为单位预读后续若干页面,以减少随机读时的磁盘寻道开销。
    在这里插入图片描述

例如,若应用以 4KB 为单位读取大型文件,内核可能在后台提前载入 128KB 或更多连续页面,由此实现“顺序读取性能≈内存读取性能”的效果。

  • 完全加载策略:若某一小文件(如几 MB)访问频率极高,可在应用启动时一次将整个文件 mmap()read() 到内存(posix_fadvise(..., POSIX_FADV_WILLNEED)),确保后续访问都命中内核缓存;

7. 缓存优化的一般思路

在实际项目中,引入进程内缓存时,可根据以下几个准则:

  1. 缓存目标场景

    • 存在稳定的数据热点(某些 key 会被反复访问);
    • 读操作远多于写操作;
    • 下游服务(数据库、远程接口)性能低,成为瓶颈;
    • 缓存一致性要求相对宽松,偶尔允许短暂的“陈旧”数据。
  2. 缓存大小与容量

    • 缓存容量过小,会导致“热点”数据被频繁淘汰,命中率低,性能提升有限;
    • 缓存容量过大,会占用大量堆空间,增加 GC 频率与时长;
    • 通常通过监控缓存命中率(cache.stats().hitRate())来调整容量,推荐至少达到 50% 的命中率,若低于 10% 就要重新评估是否需要缓存。

在这里插入图片描述

  1. 回收策略选择

    • 默认使用 LRU,即 maximumSize(...)
    • 对于需要“短期热点”或“超时失效”的数据,可结合 expireAfterWrite(...)expireAfterAccess(...)
    • 若缓存数据对象非常大,且不想占用堆内存,可考虑 weakValues()softValues(),但要避免“缓存颠簸”现象。
  2. 监控与统计

    • 开启 recordStats(),收集命中、加载、移除次数等数据;
    • 定期导出或打印 cache.stats(),分析缓存命中率(hitRate)与平均加载时间(averageLoadPenalty);
    • 若发现加载成本过高,可考虑加大缓存容量或优化加载算法;
  3. 缓存失效与一致性

    • 当缓存中数据与源数据库数据不一致时,需要设计缓存更新/清理策略(如主动失效、定时刷新或消息通知触发刷新);
    • 对于对一致性要求极高场景,可使用“双写+事务+消息队列+双删失效”等方案,见后续“缓存一致性”课时。
  4. 预加载 vs 惰性加载

    • 惰性加载(Lazy Loading):在第一次访问时加载到缓存,常见于 LoadingCache
    • 预加载(Preloading):在应用启动时或定时调度时一次性加载所有热点数据,减少首次访问延迟;
    • 若热点集合较小且可预见,可采用预加载;若热点动态且数据量大,优先使用惰性加载。

8. 缓存应用案例

  1. HTTP 304(Not Modified)缓存

    • 浏览器发送条件性请求:带上 If-Modified-SinceETag
    • 服务端判断资源是否自上次修改以来未发生变化,若无改动则直接返回 304,让浏览器使用本地缓存;否则返回 200 并携带新的资源与缓存头;
    • 这样可以在浏览器端节省一次完整的资源下载,并允许操作系统与浏览器在内存/硬盘层面做更深层次的缓存。
  2. CDN(内容分发网络)缓存

    • 用户访问某个静态资源时,会首先到就近的 CDN 节点请求;
    • 若该节点已有缓存,直接返回给用户;否则节点会向**源站(Origin)**拉取一份并缓存在本地;
    • CDN 缓存策略包括 TTL(Time-To-Live)、LRU 或 LFU,来自不同运营商或网络环境下的缓存命中率优化直接影响用户体验与带宽成本。
  3. 数据库二级缓存

    • ORM 框架(如 Hibernate)常集成二级缓存,将热点实体缓存在本地 heap 或分布式缓存中;
    • 在事务提交或数据更新时,需要将对应缓存项失效或更新;
    • 缓存失效策略与事务边界息息相关,需要设计清晰的缓存注解或 AOP 拦截器。

9. 小结

进程内缓存(堆内缓存) 的设计思路与常见实现:

  1. 缓存本质与应用场景

    • 缓存用于调和下游“慢”与上游“快”之间的速度差异;
    • 典型场景包括:热点数据查询、配置读取、会话管理、短期临时数据。
  2. Guava LoadingCache

    • CacheBuilder 提供灵活配置:maximumSizeinitialCapacityconcurrencyLevel
    • 支持手动 put() 与自动加载(CacheLoader)两种模式;
    • 可通过 invalidate() 手动移除,并通过 removalListener 监听删除事件;
    • 回收策略包括基于容量(LRU)、基于时间(expireAfterWrite/Access)与 JVM 引用回收(weakKeys/weakValues/softValues);
    • 避免“软引用缓存颠簸”带来的频繁 GC 问题。
  3. 常见缓存算法

    • FIFO:先进先出,简单但不考虑热点;
    • LRU:最近最少使用,当前最流行,保留热点;
    • LFU:最近最不常用,保留高频访问数据,支持频次计数;
  4. 简易 LRU 实现

    • 利用 LinkedHashMap 构造参数 accessOrder=true,覆写 removeEldestEntry
    • 整体逻辑简单,但不支持过期时间与并发安全,需要在生产环境中慎用或加锁。
  5. 操作系统缓存与预读

    • Linux 内核会自动执行 readahead,预读后续页面到 cached 区域;
    • 可手动使用 mmap()posix_fadvise() 等方式实现“完全加载”,适用于小文件的高频访问。
  6. 缓存优化一般思路

    • 在缓存容量、命中率与 JVM GC 之间做折中;
    • CDC(缓存、数据库、集群)技术栈常见组合;
    • 监控 cache.stats() 指标,命中率需 ≥ 50% 才有较好收益;若 < 10% 则应卸载或重构缓存策略。
  7. 示例应用

    • HTTP 304、CDN 缓存;
    • 数据库二级缓存;
    • Redis 作为分布式缓存,面向更大规模数据。

在这里插入图片描述


http://www.hkcw.cn/article/yIcMPEfKLk.shtml

相关文章

纯汇编自制操作系统(四、应用程序等的实现)

本项目已在Github开源&#xff1a;Plain-OS shell.asm ;shell.asm [bits 32]extern scroll_screen [section .data] ; Shell界面 msg db "[rootPlain]-(/)# ", 0 cmd_buffer times 80 db 0; 命令定义 cmd_echo db "echo", 0 cmd_help db "help"…

基于Android的跳蚤市场_springboot+vue

开发语言&#xff1a;Java框架&#xff1a;springboot AndroidJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.6 系统展示 APP登录 A…

概念篇:软件测试

文章目录 定义软件测试开发工程师和测试工程师的区别其他不同自动化测试技术需求的概念开发模型瀑布模型螺旋模型增量模型和迭代模型 定义 1. 软件测试就是验证软件产品特性是否满足用户的需求 2. 产品特性&#xff1a;功能&#xff0c;性能&#xff0c;界面&#xff0c;易用性…

Redis最佳实践——电商应用的性能监控与告警体系设计详解

Redis 在电商应用的性能监控与告警体系设计 一、原子级监控指标深度拆解 1. 内存维度监控 核心指标&#xff1a; # 实时内存组成分析&#xff08;单位字节&#xff09; used_memory: 物理内存总量 used_memory_dataset: 数据集占用量 used_memory_overhead: 管理开销内存 us…

郑钦文取胜后直接倒地庆祝 艰苦胜利展现顽强斗志

北京时间6月1日,2025年法网女单第四轮比赛中,中国选手郑钦文经过3盘苦战,以7-6(5)/1-6/6-3战胜萨姆索诺娃,首次晋级法网八强。这也是自2011年李娜以来,首位在法网打进女单八强的中国选手。比赛耗时2小时47分钟,胜利后郑钦文兴奋倒地庆祝。这场比赛对郑钦文来说非常艰苦。…

微软前交易主管瞄准新私募股权基金 聚焦AI与并购

克里斯・杨正计划设立一只私募股权基金,专注于收购公司、进行合并,并利用人工智能提升其运营效率。他曾领导微软风险投资和并购团队长达五年,已向昔日同事透露了他的计划。杨对收购医疗保健公司以及网络安全等软件行业企业表现出浓厚兴趣。此前,独立投资者埃拉德・吉尔和贝…

韩警方介入调查菲籍孕妇分娩悲剧 飞行途中新生儿不幸夭折

韩国济州航空一架客机1日发生意外事件,一名菲律宾籍孕妇在飞行途中足月分娩,新生儿因无呼吸心跳,经紧急送医后仍不幸死亡。目前韩国警方已展开调查。仁川机场警方表示,当日清晨6时44分接到通报,称“飞机上出生的婴儿没有呼吸”。该婴儿在心跳停止状态下被紧急送医,最终抢…

雷军再发文回应被质疑 反击华为质疑

2025年的汽车圈注定不平静。华为常务董事余承东在公开场合“暗讽”友商“产品不行却靠营销卖爆”,小米总裁卢伟冰与雷军接连发文反击,一句“诋毁,本身就是一种仰望”将矛盾推向高潮。这场看似“口水战”的交锋背后,实则是国产车企在流量时代争夺市场话语权的生死博弈。5月3…

孩子喝牛奶过敏别慌 这份应对指南超实用

在儿童的成长过程中,牛奶作为重要的营养来源,被广泛用于满足孩子们的生长需求。然而,对于一部分孩子来说,牛奶却可能成为健康的威胁。牛奶过敏,这一看似不起眼却暗藏危险的问题,正逐渐引起家长和社会的广泛关注。今天,“健康北京”带领家长们深入探讨孩子喝牛奶过敏的相…

智能制造之精读——场景化落地应用推进制造企业数字化转型【附全文阅读】

主要围绕制造企业数字化转型展开&#xff0c;先分析现状&#xff0c;指出面临人力成本上升等挑战&#xff0c;强调智能工厂是转型关键。接着阐述信息化建设思路&#xff0c;涵盖支撑体系、数据底层建设和应用平台搭建&#xff0c;明确建设目标与举措。 然后介绍典型场景案例&am…

Efficient Combination of

Teacher B network f T B _{TB} TB​ 补充信息 作者未提供代码

系统性学习C语言-第十三讲-深入理解指针(3)

系统性学习C语言-第十三讲-深入理解指针&#xff08;3&#xff09; 1. 数组名的理解2. 使用指针访问数组3. ⼀维数组传参的本质4. 冒泡排序5. ⼆级指针 6. 指针数组7. 指针数组模拟二维数组 1. 数组名的理解 在上⼀个章节我们在使用指针访问数组的内容时&#xff0c;有这样的代…

图吧工具箱安装提示病毒文件解决记录

图吧工具箱安装提示病毒文件解决记录 系统&#xff1a;win10 安装位置&#xff1a;U盘 操作&#xff1a; 1、window安全中心-病毒和威胁防护-实时保护&#xff1a;关闭 2、安装工具箱 3、开启实时保护正常打开工具箱检测

【从零开始学习QT】信号和槽

目录 一、信号和槽概述 信号的本质 槽的本质 二、信号和槽的使用 2.1 连接信号和槽 2.2 查看内置信号和槽 2.3 通过 Qt Creator 生成信号槽代码 自定义槽函数 自定义信号 自定义信号和槽 2.4 带参数的信号和槽 三、信号与槽的连接方式 3.1 一对一 &#xff08;1&…

教授为选麦种晒到脱皮妻子心疼落泪 客厅变“麦场”

堆满麦穗的客厅里,一位“老农”打着赤膊认真筛选着麦子。河南科技大学农学院教授王林生长年致力于小麦遗传育种研究。每年麦收时节,他家的客厅、阳台甚至书房都变成了他的“麦场”,到处堆满了金黄色的麦子和打包好的麦种。责任编辑:zx0001

印度81人因“同情”巴基斯坦被逮捕 社交媒体发帖引争议

印度阿萨姆邦首席部长萨尔马于6月1日宣布,该邦有81人因“同情”巴基斯坦被警方逮捕。此前,印巴两国因印控克什米尔地区枪击事件发生严重冲突。萨尔马在声明中提到,印度一直在追踪社交媒体上反国家的帖子并采取行动。据当地警方消息,其中一人因为在Instagram上发布巴基斯坦国…

日本北海道附近海域发生5.9级地震 地震频发引关注

北京时间6月2日2时51分,日本北海道附近海域发生5.9级地震,震源深度55公里,震中位于北纬41.80度,东经143.75度。此前,当地时间5月31日17时37分左右,该地区还发生了一次6.1级地震,最大震感为震度4,震源深度20公里。近期,一则关于日本将在7月5日迎来大灾难的预言在社交平…

基于python大数据的音乐可视化与推荐系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

力扣HOT100之动态规划:416. 分割等和子集

这道题之前刷过代码随想录&#xff0c;现在只能想起一点点思路&#xff0c;最后还是去看视频了。这道题用二维dp数组或者一维dp数组都可以做&#xff0c;这篇博客把两种思路都讲一下。 二维dp数组做法 原问题可以抽象为&#xff1a;容量为sum / 2的背包能否用数组中的物品填满…

【学习笔记】Sparse Crosscoders for Cross-Layer Features and Model Diffing

Sparse Crosscoders for Cross-Layer Features and Model Diffing Abstract 本说明介绍了稀疏跨编码器(sparse crosscoders)&#xff0c;它是一种稀疏自编码器(sparse autoencoders)或transcoders的变体&#xff0c;旨在用于理解叠加中的模型结构。SAEs是在单一层中编码和预测…