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

实战——缓存的使用

文章目录

  • 前言
  • 概述
  • 实践
    • 一、缓存数据一致
      • 1.更新缓存类
      • 2.删除缓存类
    • 二、项目实践(商城项目)
      • 缓存预热
      • 双缓存机制


前言

对于我们日常开发的应用系统。由于MySQL等关系型数据库读写的并发量是有一定的上线的,当请求量过大时候那数据库的压力一定会上来。

所以采用 MySQL+Redis 这对经典组合来解决高并发问题的。Redis 作为 MySQL 的前置缓存,可以应对绝大部分查询请求,从而在很大程度上缓解 MySQL 并发请求的压力,但是不能一说到缓存脑海中就只有 Redis,这无论在工作还是面试中都不合适,所以我们先全面了解缓存。

注意:缓存不止有redis,需要全面的了解缓存


概述

  • 缓存大体可以分为三类(意思就是在整个系统中我们每一层都是有缓存的):
    • 客户端缓存;
    • 服务端缓存;
    • 网络中的缓存。
  • 根据规模和部署方式缓存也可以分为:
    • 单体缓存;
    • 缓存集群;
    • 分布式缓存。

我们通过对每一层进行缓存来提高系统的稳定性和效率。


实践

一、缓存数据一致

不论是本地缓存还是redis,我们的基本思路就是:当缓存没有命中的时候,我们就去数据库查询,然后直接放到缓存中,供下次查询以加快查询效率。
但是我们在修改数据的时候,就可能造成数据库和缓存数据一致性的问题。
有好几种解决方案,(两大类:一:更新;二:删除)1. 先更新缓存,再更新数据库2. 先更新数据库,再更新缓存3、先删除缓存,后更新数据库4、先更新数据库,后删除缓存

1.更新缓存类

不论先更新数据库还是先更新缓存,这两种方案都不可取。原因就是不论我们先更新谁后更新谁,就会导致我们前面更新成功后,后面更新的那个万一挂了,我们就难以判断是否成功。所以这类更新的方案,对我们来说都是不可取的。

2.删除缓存类

  • 2.1 先删缓存,后更新数据库
    • 问题:

      • 线程A删除缓存后,更新DB,但是DB的事务并没有提交,线程B进来访问。那么就会重新更新缓存(造成缓存和DB数据不一致)
        在这里插入图片描述
    • 解决方案

      • 使用延时双删
        • 1.先删除缓存,再去更新DB
        • 2.当DB更新成功之后,延时个1s,再删除一次缓存

  • 2.2 先更新数据库,后删除缓存(开发中常用的策略)

    • 问题:

      • 在缓存失效的且并发的时候会发生(虽然概率比较小但是还是会发生,因为概率小所以我们在开发中常用)
        在这里插入图片描述
    • 解决方案:

      • 1.设置缓存失效时间。
      • 2.异步延时删除机制(问题在于当我们删除缓存的时候万一失败需要补偿机制来保证缓存一定删除)
        异步补偿删除方案一:
        在这里插入图片描述

    异步补偿删除方案二:

    由于方案一中的业务代码的耦合性较高。使用订阅数据库的binlog

在这里插入图片描述

说到底就是通过数据库的 binlog 来异步淘汰 key,利用工具(canal)将 binlog
日志采集发送到 MQ 中,然后通过 ACK 机制确认处理删除缓存。
先更新 DB,后删除缓存,这种方式,被称为 Cache Aside Pattern,属于缓存更新的设计模式之一。(这是一种最为标准的方案)


二、项目实践(商城项目)

我这边以京东商城为例

在这里插入图片描述

像这样的商城首页一定是并发最高的地方,如果我们每次都去数据库查询,很显然是不满足我们高并发的要求的。

像这种任何用户看到的都是一样的结果的数据,在缓存中的命中率是比较高得,所以我们可以考虑引入缓存的方式。
并且我们这里完全可以分为多个key,如促销,轮播图,标签等。

  1. 首页缓存使用
// 大佬的代码例子public HomeContentResult getFromRemote(){List<PmsBrand> recommendBrandList = null;List<SmsHomeAdvertise> smsHomeAdvertises = null;List<PmsProduct> newProducts  = null;List<PmsProduct> recommendProducts  = null;HomeContentResult result;/*从redis获取*/if(promotionRedisKey.isAllowRemoteCache()){recommendBrandList = redisOpsUtil.getListAll(promotionRedisKey.getBrandKey(), PmsBrand.class);smsHomeAdvertises = redisOpsUtil.getListAll(promotionRedisKey.getHomeAdvertiseKey(), SmsHomeAdvertise.class);newProducts = redisOpsUtil.getListAll(promotionRedisKey.getNewProductKey(), PmsProduct.class);recommendProducts = redisOpsUtil.getListAll(promotionRedisKey.getRecProductKey(), PmsProduct.class);}/*redis没有则从微服务中获取*/if(CollectionUtil.isEmpty(recommendBrandList)||CollectionUtil.isEmpty(smsHomeAdvertises)||CollectionUtil.isEmpty(newProducts)||CollectionUtil.isEmpty(recommendProducts)) {result = promotionFeignApi.content(0).getData();}else{result = new HomeContentResult();result.setBrandList(recommendBrandList);result.setAdvertiseList(smsHomeAdvertises);result.setHotProductList(recommendProducts);result.setNewProductList(newProducts);}return result;}

redis 初始化key代码初始化注解@PostConstruct

@Service
@Slf4j
public class PromotionRedisKey {// 配置@Value ("${namespace.promotion:prmtd}")private String promotionNamespace;@Value ("${promotion.brand:br}")private String brand;@Value ("${promotion.newProduct:np}")private String newProduct;@Value ("${promotion.recProduct:rp}")private String recProduct;@Value ("${promotion.homeAdvertise:hd}")private String homeAdvertise;@Value ("${promotion.seckill:sk}")private String secKill;// 需要初始化的keyprivate String brandKey;private String newProductKey;private String recProductKey;private String homeAdvertiseKey;private String secKillKey;// 全局缓存控制开关@Value("${promotion.demo.allowLocalCache:true}")private boolean allowLocalCache;@Value("${promotion.demo.allowRemoteCache:true}")private boolean allowRemoteCache;/*** 该注解的方法在整个Bean初始化中的执行顺序:** Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的初始化方法)** 该注解的功能:当依赖注入完成后用于执行初始化的方法,并且只会被执行一次*/@PostConstructpublic void initKey(){brandKey = promotionNamespace + "." + brand;newProductKey = promotionNamespace + "." + newProduct;recProductKey = promotionNamespace + "." + recProduct;homeAdvertiseKey = promotionNamespace + "." + homeAdvertise;secKillKey = promotionNamespace + "." + secKill;StringBuilder logKeyStr = new StringBuilder();logKeyStr.append("[品牌推荐redis主键=").append(brandKey).append("] [新品推荐redis主键=").append(newProductKey).append("] [人气推荐redis主键=").append(recProductKey).append("] [轮播广告redis主键=").append(homeAdvertiseKey).append("] [秒杀redis主键=").append(secKillKey).append("]");log.info("促销系统Redis主键配置:{}",logKeyStr);}public String getBrandKey() {return brandKey;}public String getNewProductKey() {return newProductKey;}public String getRecProductKey() {return recProductKey;}public String getHomeAdvertiseKey() {return homeAdvertiseKey;}public String getSecKillKey() {return secKillKey;}public boolean isAllowLocalCache() {return allowLocalCache;}public boolean isAllowRemoteCache() {return allowRemoteCache;}
}

通过以上首页对缓存的使用,提出一些思考如下:
缓存一定是离用户越近越好,依据这个原则,首页还有优
化的空间,从上面的访问路径可以看到,首页服务需要到 Redis 集群中获得数据用以展示,能不能将缓存的数据再提前呢?于是我们在首页服务内引入了应用级缓存 Caffeine。

什么叫近???
在这里插入图片描述

TIPS:Caffeine 基于 Google 的 Guava Cache,提供一个性能卓越的本地缓存(local cache) 实现, 也是 SpringBoot 内置的本地缓存实现,有资料表明 Caffeine性能是 Guava Cache 的 6 倍

Caffeine使用

@Configuration
public class CaffeineCacheConfig {@Bean(name = "promotion")// 缓存预热(指定bean名称)public Cache<String, HomeContentResult> promotionCache() {int rnd = ThreadLocalRandom.current().nextInt(10);return Caffeine.newBuilder()// 设置最后一次写入经过固定时间过期.expireAfterWrite(30 + rnd, TimeUnit.MINUTES)// 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).build();}/*以双缓存的形式提升首页的访问性能,这个备份缓存其实设置为永不过期更好,* 可以作为首页的降级和兜底方案* 为了说明缓存击穿和分布式锁这里设置了一个过期时间*/@Bean(name = "promotionBak")public Cache<String, HomeContentResult> promotionCacheBak() {int rnd = ThreadLocalRandom.current().nextInt(10);return Caffeine.newBuilder()// 设置最后一次访问经过固定时间过期.expireAfterAccess(41 + rnd, TimeUnit.MINUTES)// 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).build();}/*秒杀信息在首页的缓存*/@Bean(name = "secKill")public Cache<String, List<FlashPromotionProduct>> secKillCache() {int rnd = ThreadLocalRandom.current().nextInt(400);return Caffeine.newBuilder()// 设置最后一次写入经过固定时间过期.expireAfterWrite(500 + rnd, TimeUnit.MILLISECONDS)// 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).build();}/*秒杀信息在首页的缓存备份,提升首页的访问性能*/@Bean(name = "secKillBak")public Cache<String, List<FlashPromotionProduct>> secKillCacheBak() {int rnd = ThreadLocalRandom.current().nextInt(400);return Caffeine.newBuilder()// 设置最后一次写入经过固定时间过期.expireAfterWrite(100 + rnd, TimeUnit.MILLISECONDS)// 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).build();}
}
@Autowired@Qualifier("promotion") // 指定注入相关对象和上面的配置一致,就是在容器中拿对应的值private Cache<String, HomeContentResult> promotionCache;@Overridepublic HomeContentResult cmsContent(HomeContentResult content) {//获取推荐专题content.setSubjectList(homeDao.getRecommendSubjectList(0,4));return content;}/*处理首页推荐品牌和商品内容*/@Overridepublic HomeContentResult recommendContent(){/*品牌和产品在本地缓存中统一处理,有则视为同有,无则视为同无*/final String brandKey = promotionRedisKey.getBrandKey();final boolean allowLocalCache = promotionRedisKey.isAllowLocalCache();/*先从本地缓存中获取推荐内容*/HomeContentResult result = allowLocalCache ?promotionCache.getIfPresent(brandKey) : null;if(result == null){result = allowLocalCache ?promotionCacheBak.getIfPresent(brandKey) : null;}/*本地缓存中没有*/if(result == null){log.warn("从本地缓存中获取推荐品牌和商品失败,可能出错或禁用了本地缓存[allowLocalCache = {}]",allowLocalCache);// 去redis中去,没有再去DB中取result = getFromRemote();if(null != result) {promotionCache.put(brandKey,result);promotionCacheBak.put(brandKey,result);}}/* 处理秒杀内容*/final String secKillKey = promotionRedisKey.getSecKillKey();List<FlashPromotionProduct> secKills = secKillCache.getIfPresent(secKillKey);if(CollectionUtils.isEmpty(secKills)){secKills = secKillCacheBak.getIfPresent(secKillKey);}if(CollectionUtils.isEmpty(secKills)){/*极小的概率出现本地两个缓存同时失效的问题,从远程获取时,只从Redis缓存中获取,不从营销微服务中获取,避免秒杀的流量冲垮营销微服务*/secKills = getSecKillFromRemote();if(!CollectionUtils.isEmpty(secKills)) {secKillCache.put(secKillKey,secKills);secKillCacheBak.put(secKillKey,secKills);}else{/*Redis缓存中也没有秒杀活动信息,此处用一个空List代替,* 其实可以用固定的图片或信息,作为降级和兜底方案*/secKills = new ArrayList<FlashPromotionProduct>();}}result.setHomeFlashPromotion(secKills);// fixme CMS本次不予实现,设置空集合result.setSubjectList(new ArrayList<CmsSubject>());return result;}

缓存预热

缓存预热是为了防止,我们的项目刚发版,可能请求过多造成的数据库压力过大的情况。

使用Spring的启动化机制

@Component
@Slf4j
// 缓存预热,使用Spring启动化机制CommandLineRunner
public class preheatCache implements CommandLineRunner {@Autowiredprivate HomeService homeService;@Overridepublic void run(String... args) throws Exception {for (String str : args) {log.info("系统启动命令行参数: {}", str);}// 缓存预热,可以包括本地缓存或者redishomeService.preheatCache();}}

双缓存机制

在这里插入图片描述

为了数据的一致性,本地 Caffeine和redis设置了过期时间,Redis 集群中的数据也会在数据变动后被除。当数据同时过期的时候。可能有以下的情况本地缓存去redis去取数据;本地缓存取DB取数据。那么在耗时上就会产生毛刺现象。


为了避免以上情况,我们使用双缓存的结构。

    @Bean(name = "promotion")// 缓存预热public Cache<String, HomeContentResult> promotionCache() {int rnd = ThreadLocalRandom.current().nextInt(10);return Caffeine.newBuilder()// 设置最后一次写入经过固定时间过期.expireAfterWrite(30 + rnd, TimeUnit.MINUTES)// 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).build();}备份缓存要随着主缓存的变动而变动/*以双缓存的形式提升首页的访问性能,这个备份缓存其实设置为永不过期更好,* 可以作为首页的降级和兜底方案* 为了说明缓存击穿和分布式锁这里设置了一个过期时间*/@Bean(name = "promotionBak")public Cache<String, HomeContentResult> promotionCacheBak() {int rnd = ThreadLocalRandom.current().nextInt(10);return Caffeine.newBuilder()// 设置最后一次访问经过固定时间过期.expireAfterAccess(41 + rnd, TimeUnit.MINUTES)// 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).build();}

相关文章:

实战——缓存的使用

文章目录前言概述实践一、缓存数据一致1.更新缓存类2.删除缓存类二、项目实践&#xff08;商城项目&#xff09;缓存预热双缓存机制前言 对于我们日常开发的应用系统。由于MySQL等关系型数据库读写的并发量是有一定的上线的&#xff0c;当请求量过大时候那数据库的压力一定会上…...

2023年中职网络安全竞赛跨站脚本渗透解析-2(超详细)

跨站脚本渗透 任务环境说明:需求环境可私信博主! 服务器场景:Server2126(关闭链接)服务器场景操作系统:未知访问服务器网站目录1,根据页面信息完成条件,将获取到弹框信息作为flag提交;访问服务器网站目录2,根据页面信息完成条件,将获取到弹框信息作为flag提交;访问…...

Scala的简单使用

文章目录Scala的简单使用&#xff08;一&#xff09;交互模式1、命令行方式2、文件方式&#xff08;二&#xff09;编译模式1、创建源程序2、编译成字节码3、解释执行对象Scala的简单使用 Scala可以在交互模式和编译模式两种方式下运行 &#xff08;一&#xff09;交互模式 在…...

Java之前缀和算法

目录 一.前缀和 1.前缀和介绍 2.编程中的前缀和 二.一维数组的动态和 1.题目描述 2.问题分析 3.代码实现 三.除自身以外数组的乘积 1.题目描述 2.问题分析 3.代码实现 四.和为 K 的子数组 1.题目描述 2.问题分析 3.代码实现 五.形成两个异或相等数组的三元组数目…...

基于GIS计算降雨侵蚀力R因子

一、数据来源介绍 &#xff08;一&#xff09;行政边界数据 本文所用到的河北唐山行政边界数据来源于中国科学院资源环境科学与数据中心&#xff08;https://www.resdc.cn/Default.aspx&#xff09;。 &#xff08;二&#xff09;降水量数据 本文所用到的降水量数据来源于国家…...

大数据时代下的企业网络安全

在大数据技术迅猛发展的今天&#xff0c;网络安全问题已经发展成一个广受关注的热门研究方向。有人说&#xff0c;“大数据下&#xff0c;人人裸奔”&#xff0c;隐私保护、数据防护日益成为广大学者、企业研究的焦点。 面对这种安全威胁&#xff0c;企业必须实施一些有效的信…...

【跟我一起读《视觉惯性SLAM理论与源码解析》】第三章第四章 SLAM中常用的数学基础知识相机成像模型

齐次坐标能大大简化在三维空间中点、线、面表达方式和旋转、平移等操作在齐次坐标下&#xff0c;两个点的叉积结果可以表示一条直线l;也可以用两条直线的叉积结果表示它们的齐次坐标交点&#xff0c;关于叉积其实十四讲解释的还是比较清楚的&#xff0c;和李代数李群的关系可以…...

LeetCode 242. 有效的字母异位词

242. 有效的字母异位词 难度&#xff1a;easy\color{Green}{easy}easy 题目描述 给定两个字符串 sss 和 ttt &#xff0c;编写一个函数来判断 ttt 是否是 sss 的字母异位词。 注意&#xff1a; 若 sss 和 ttt 中每个字符出现的次数都相同&#xff0c;则称 sss 和 ttt 互为字…...

力扣mysql刷题记录

mysql刷题记录 刷题链接https://leetcode.cn/study-plan/sql/?progressjkih0qc mysql冲&#xff01;mysql刷题记录1699. 两人之间的通话次数1251. 平均售价1571. 仓库经理1445. 苹果和桔子1193. 每月交易 I1633. 各赛事的用户注册率1173. 即时食物配送 I1211. 查询结果的质量…...

Linux基础命令-lsof查看进程打开的文件

Linux基础命令-uptime查看系统负载 Linux基础命令-top实时显示系统状态 Linux基础命令-ps查看进程状态 文件目录 前言 一 命令的介绍 二 语法及参数 2.1 使用help查看命令的语法信息 2.2 常用参数 2.2.lsof命令-i参数的条件 三 命令显示内容的含义 3.1 FD 文件描述符的…...

常用电平标准

现在常用的电平标准有TTL CMOS LVTTL LVCMOS LVDS PCI等&#xff0c;下面简单介绍一下各自的供电电源、电平标准及注意事项数字电路中&#xff0c;由TTL电子元件组成电路使用的电平。电平是个电压范围。标准输出高电平(VOH): 2.4V标准输出低电平(VOL)&#xff1a;0.4V通常输出高…...

小程序开发注意点

1.组件样式隔离注意点 2.methods方法 3.自定义组件的properties参数 4.自定义组件的事件监听 5.纯数据字段 6.插槽 单个插槽 启用多插槽 使用多个插槽 7.属性绑定实现父传子功能 例如在这里有一个组件为<one></one>&#xff0c;那么可以在组件当中传入参数 &l…...

自行车出口欧盟CE认证,新版自行车标准ISO 4210:2023与ISO 8098:2023发布

2023年1月&#xff0c;国际标准化组织ISO发布了新版“自行车以及儿童自行车的测试标准”&#xff0c;即ISO 4210&#xff1a;2023以及ISO 8098:2023&#xff0c;用于取代了SO 4210&#xff1a;2015以及ISO 8098:2015。新版标准一经发布&#xff0c;立即生效。欧盟标准化委员会C…...

2020蓝桥杯真题回文日期 C语言/C++

题目描述 2020 年春节期间&#xff0c;有一个特殊的日期引起了大家的注意&#xff1a;2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202&#xff0c;恰好是一个回文数。我们称这样的日期是回文日期。 有人表示 20200202 是 “千年一遇…...

postman入门到精通之【接口知识准备】(一)

postman入门到精通之【接口知识准备】&#xff08;一&#xff09; 目录&#xff1a;导读 前言 接口测试概念 接口测试 接口测试的原理 常用接口测试工具 接口测试基础知识 接口的定义 接口的分类 HTTP接口 Web Service接口 RESTful接口 HTTP请求 统一资源定位符&…...

【算法数据结构体系篇class07】:加强堆

一、手动改写堆&#xff08;非常重要&#xff09;&#xff01;系统提供的堆无法做到的事情&#xff1a;1&#xff09;已经入堆的元素&#xff0c;如果参与排序的指标方法变化&#xff0c;系统提供的堆无法做到时间复杂度O(logN)调整&#xff01;都是O(N)的调整&#xff01;2&am…...

Taro3.x 容易踩坑的点(阻止滚动穿透,弹框蒙层父级定位)

解决弹框滚动的时候&#xff0c;下层也会滚动问题》阻止滚动穿透(react,vue)案例描述&#xff1a;页面展示时需要滚动条才可以显示完整&#xff0c;但是当我们显示弹框的时候&#xff0c;即使不需要滚动条&#xff0c;但是页面仍然可以滚动&#xff0c;并且下层内容会随着滚动变…...

SpringBoot+ActiveMQ-发布订阅模式(消费端)

ActiveMQ消息中间件的发布订阅模式 主题 topictopic生产端案例(配合topic消费端测试)&#xff1a;SpringBootActiveMQ Topic 生产端ActiveMQ版本&#xff1a;apache-activemq-5.16.5案例源码:SpringBootActiveMQ-发布订阅DemoSpringBoot集成ActiveMQ Topic消费端的pom.xml<?…...

vscode下使用arduino插件开发ESP32 Heltec WiFi_Kit_32_V3

下载vsCode 添加 arduino 插件 在Arduino IDE 中添加开发板&#xff0c;注意只能用右侧的开发板管理器添加&#xff0c;自己下载之后复制进去的IDE认&#xff0c;但是vsCode不认&#xff0c;搜索ESP32 第一个库里面只有到V2的&#xff0c;没有V3&#xff0c;要安装下面那个 H…...

吐血整理AutoSAR Com-Stack 的配置【基于ETAS】

总目录链接>> AutoSAR入门和实战系列总目录 文章目录01.软件组件和系统说明02.基本软件配置03.系统数据映射04.代码生成05.代码整合06.测试下图显示了基于 AUTOSAR 的 ECU SW 的结构。纵观BSW&#xff0c;大体分为三层。三层模块中&#xff0c;与通信相关的模块称为通信…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...