Redis学习:BigKey、缓存双写一致性更新策略和案例

news2024/11/5 8:59:38

Redis学习:BigKey、缓存双写一致性更新策略和案例

文章目录

  • Redis学习:BigKey、缓存双写一致性更新策略和案例
    • 1. BigKey
    • 2. 缓存双写一致性更新策略
    • 3. 缓存双写一致性案例

1. BigKey

  1. 面试题
    1. MoreKey不可以使用keys * ,要使用SCAN基于游标来查询所有的key
    2. 通过在redis.conf配置文件中修改SECURITY配置项,将这些指令重命名或者禁用
    3. MEMORY USAGE key查询指定key所占用的字节数,也可以使用redis-cli –bigkeys查看每个类型占用字节最多的key,以及key的个数和平均大小
    4. BigKey是指某个key的value太大string类型超过10k,其他类型hash\list\set\zset超过5000个元素就是bigkeystring类型可以直接使用del阻塞删除,其他类型不可以使用del,会造成阻塞,而是用渐进式删除,一部分一部分进行删除,通过HSCAN\SSCAN\ZSCAN来获取对应类型key中value中的数据,然后一部分一部分进行删除
    5. BigKey调优,因为redis有del阻塞删除和unlink非阻塞删除,而默认使用del阻塞删除,故可以在redis.conf配置文件中修改LAZYFREE配置项实现非阻塞删除,以进行优化
    6. MoreKey时,不可以直接使用Keys * 进行遍历,会严重阻塞,要使用SCAN 游标 模式 个数 命令基于游标进行遍历所有的key,每次会返回下一次遍历开始的游标以及近似个数的匹配的key
    7. MoreKey是指redis中key的个数过多而BigKey是指某个Key的value过大
    8. SCAN是遍历KeyHSCAN\SSCAN\ZSCAN是遍历指定类型key中的value
  2. MoreKey案例(简历加分)
    1. 向Redis中插入大量数据
      1. 先使用linux操作创建一个文件,里面存放了一百万条set指令,使用管道指令将所有的指令在Redis中运行
      2. 使用DBSIZE可以查看Redis数据库中的key的个数
    2. 禁用keys * 等指令
      1. 数据量很大时,一定要避免使用keys * ,可以直接在配置文件中禁止该指令
      2. 当数据量很大时,不要使用keys * 和flushdb因为Redis只有主线程串行执行命令,且keys * 是遍历实现的,故会非常耗费时间,造成Redis主线程卡顿,则此时后面的所有请求的命令均会卡顿
      3. 通过在redis.conf配置文件中设置SECURITY配置项禁止这些命令,或者重命名,更改配置文件后一定要先重启服务端
    3. 使用SCAN遍历Morekey
      1. SCAN是从游标开始遍历指定个数的匹配的key而HSCAN\SSCAN\ZSCAN是遍历指定类型key中value的元素,是删除BigKey时遍历当前key中的元素进行删除
      2. 当redis数据库中key很多时,要禁止使用keys * 、FLUSHDB等危险指令,可以在redis.conf的SECURITY配置项中进行配置,此时如果要遍历数据库中的key,要使用SCAN指令基于游标进行遍历,SCAN指令是遍历所有的key,可以指定匹配的模式,以及遍历的大概数目,且返回下一次遍历的游标,当游标为0时说明遍历结束
      3. SCAN 游标 匹配模式 个数:SCAN是基于游标的迭代,每次要指定一个游标,返回下一次开始的游标以及近似数量的key,当游标返回0时说明匹配的key遍历结束
      4. 使用scan命令查找指定的key(不使用keys * )使用SCAN遍历匹配的key,使用HSCAN/SSCAN/ZSCAN遍历指定 key(bigkey) 中的元素
      5. Scan命令用于迭代数据库中的数据库键,是基于游标的迭代器,当前遍历要基于上一次遍历的游标
      6. SCAN命令基于游标来遍历数据库中的所有key,游标从0开始,每次返回下一次遍历的游标和当前遍历的key(不保证数量),不是顺序遍历,而是高位进位加法遍历
      7. SCAN命令的意思就是对所有满足条件的key进行非顺序遍历,而是基于游标遍历,每次返回模糊数量的key,以及下一次遍历游标,直到所有的遍历结束返回游标0
      8. SCAN遍历所有的key,不是顺序遍历,而是基于游标进行遍历,高位加法遍历
  3. BigKey案例(key的value非常大)
    1. 多大的key算big
      1. MoreKey是指key非常多,BigKey是指某个key的value非常大
      2. BigKey是指value非常大,不是key大
      3. 非字符串的bigkey,不要使用del删除,而且要注意过期时间,当过期后会自动使用del进行删除,字符串的bigKey使用del进行阻塞删除,而非string的bigKey要使用渐进式删除,一部分一部分删除,或者使用lazyfree,要在配置文件中进行配置,默认是关闭的
      4. string类型的key的value最大是512M,但超过10K就是bigkey
      5. list\hash\set\zset类型的key,最多可以2^32 - 1 个元素,但数量超过5000就是bigkey
    2. 哪些危害:内存不均、超时删除、网络阻塞
    3. 如何产生:社交粉丝、报表积累
    4. 如何发现
      1. 使用redis-cli --bigkeys可以返回每个数据类型的最大的bigkey,以及该类型key的数目和平均大小,此时可以对最大的bigkey进行删除,string类型可以直接阻塞del删除,但非string不要使用del,而是渐进式删除,且对于key,可以通过MEMORY USAGE key,查看某个key所占用的内存字节数
      2. redis-cli –bigkeys
        1. 给出每个数据结构最大的bigkey,同时给出每个数据类型的个数 + 平均大小
        2. 只给出TOP1的bigkey无法查询所有的bigkey,要使用SCAN查询所有的key,并使用MEMORY USAGE key查看某个key占用内存
        3. –bigkeys底层使用SCAN进行扫描,可以使用 -i time 添加每100个SCAN的时间间隔
      3. MEMORY USAGE key
        1. 给出指定的key所占用的字节数
    5. 如何删除bigkey
      1. 非string类型先使用HSCAN/SSCAN/ZSCAN遍历指定key中的部分value,然后删除继续遍历,一部分一部分渐进式删除
      2. 使用HSCAN\ZSCAN\SSCAN遍历的是指定类型key中value的元素,然后再渐进式删除,遍历指定key中的value,再使用渐进式删除一部分一部分删除,字符串类型直接阻塞del删除,非string使用渐进式删除,且所有的key过期后均会默认使用del阻塞删除,要通过配置lazyfree配置项来开启非阻塞删除,key到期后默认使用del删除
      3. 非字符串的bigkey,不要使用del(del会直接全部删除),要使用渐进式删除,一部分一部分的删除,不要直接全部删除,且key过期后会自动默认使用del进行删除造成阻塞
      4. string类型使用del进行删除,或者使用unlink异步删除
      5. 非string类型不要用del直接删除,因为太大时会造成网络阻塞,要使用渐进式删除,一部分一部分删除
      6. hash类型使用渐进式删除,一部分一部分删除,通过HSCAN key查看当前hash类型的bigkey中的部分value,然后删除,继续遍历,一部分一部分渐进式删除,不要一下使用del全部删除
      7. list类型使用 LTRIM start end 进行修建,不在区间内的将被删除,list类型使用LTRIM修建,不在区间内的全部删除,故每次可以只修建前面指定个数的元素,直到末尾
      8. set类型使用SREM
  4. BigKey生产调优 LazyFree配置项
    1. key过期默认是使用del阻塞删除的,如果对于string可以,但对于非string不要使用del进行删除,此时就应该修改配置文件,对lazyfree配置项进行配置,已开启非阻塞删除
    2. 默认是使用del阻塞删除的,故可以通过在配置文件中修改FLAZYFREE配置使其非阻塞删除进行优化
    3. redis提供两种删除方法:del(阻塞)、unlink(非阻塞)默认是使用del阻塞删除,在配置文件中修改lazyfree配置项

2. 缓存双写一致性更新策略

  1. 面试题:写策略
    1. 缓存和数据库一致性问题:更新数据时要保证MySQL数据库的准确性,故先更新MySQL再删除缓存,此时会出现脏读,但可以保证最终一致性;读取数据时,当缓存不存在则要从MySQL读取,如果高并发必须加锁,否则会全打到MySQL上,而且加锁后要再检查是否已经写入缓存,此时就可以一次MySQL操作实现缓存回写,即双检加锁;如果先删除缓存再更新数据库,则为了保证最后的一致性,在MySQL更新前如果有读取缓存,则会从旧的MySQL中读出数据并写回缓存,此时MySQL更新后因为不会重新删除缓存,就会导致不一致,故要使用双删延迟,即先删除缓存,然后更新数据库,然后延迟一个读操作保证之间的读操作已经写回缓存最后再删除缓存,此时就算有读操作也是从更新后的数据库读取数据写入缓存
    2. 为了保证MySQL和redis缓存的一致性,可以使用canal中间件对MySQL的增量文件进行解析订阅和消费,其实时监控MySQL的binlog,可以在canal客户端连接canal服务端然后subscribe订阅指定数据库的库和表,此时就可以获得增量文件中未确认的数据,即变动的数据,然后对这些数据打印并进行相应的处理,以实现和Redis缓存的一致性
  2. 缓存双写一致性
    1. 一致性,如果redis中有数据则必须与数据库一致;如果redis无数据,则保证数据库中为最新值,且要准备写入redis
    2. 缓存可以分为只读缓存和读写缓存对于只读缓存不需要回写操作,对于读写缓存必须保证回写的一致性
    3. 对于读写缓存,当redis中无数据时,有两种回写策略:同步直写和异步缓写同步直写是将数据库数据直接写入redis缓存异步缓写是先不写入缓
    4. 如何实现:当读取redis无数据时,要使用双检加锁来防止MySQL击穿
      1. 双检加锁策略
        1. 检查两次缓存是否存在第一次不存在时加锁访问MySQL将数据写入缓存且在锁里再进行一次检查保证只有一次查询MySQL,防止击穿MySQL
        2. 当同时查询缓存时,如果存在则直接返回,否则对第一个查询数据上加锁,由一个线程去查询并写入缓存,且在锁里面再做一次查询,此时后边等待的进程进入锁后会直接返回,保证只进行一次MySQL查询
      2. 当并发量很大时,缓存不存在时可能全部去MySQL查找造成缓存击穿,且可能会redis数据覆盖,故必须使用双检加锁策略,读取redis数据时必须使用双检加锁,第一次检查缓存无数据时,加锁去从MySQL中读取数据,且在锁中再检查一次,不存在时再去读取MySQL,此时就可以保证只有一次访问MySQL;更新数据时,使用先更新数据库再删除缓存策略,或者双删延迟
      3. 当并发量很小时,可以如下写法,可以不加锁,但并发量很大时,必须加锁访问MySQL
  3. 数据库和缓存一致性的几种更新策略
    1. 以MySQL写入库的数据为准,要保证最终一致性
    2. 可以停机的情况
      1. 直接停机后保证数据的一致性
    3. 不可以停机更新策略
      没有完美的方案都不可避免的会出现脏读,但要保证最终数据的一致性
      只有缓存不存在时才会从MySQL中读取数据并回写,当更新MySQL后不会进行回写,更新MySQL数据库后不会回写进入缓存,但读取redis不存在时会双检加锁读取MySQL再写入redis,要保证以MySQL为准,故必须先更新MySQL
      1. 先更新数据库再更新缓存×
        1. 如果缓存更新失败会导致不一致,更新缓存时可能导致不一致
        2. 先更新数据库再删除缓存不会造成最终的数据不一致,但要是更新缓存则会造成数据不一致
        3. 且并发执行时,缓存更新结果可能不一致
      2. 先更新缓存再更新数据库×
        1. 要保证以MySQL为准,故必须先更新MySQL
        2. 不推荐,因为要以MySQL为准,故要保证MySQL数据库始终正确
        3. 且高并发下也会出现顺序错误,有快有慢使得更新顺序错误
      3. 先删除缓存再更新数据库
        1. 因为更新后不会修改redis,故可能会造成最终数据的不一致,故必须使用双删延迟
        2. 延时双删:就是更新前先删除缓存的值,然后更新,更新后再删除缓存的值第二次删除要延时一个读操作的时间保证读操作已经回写进入缓存后再进行删除,此时不可避免的会出现有一次读操作会读到脏数据,但可以保证最终数据一致性,但是一次读操作时间不好估计
        3. 如果不使用延时双删,则可能会导致缓存和数据库始终不一致,如还未 更新MySQL就读缓存将旧数据放入缓存中,此时MySQL更新完成,则此时的缓存和MySQL就不一致更新完MySQL后不会再更新缓存,故必须延时双删
        4. 当缓存中不存在时,就回去MySQL数据库中查找值
        5. 可能出现A更新MySQL还未完成时,B读缓存不存在然后读MySQL并回写缓存,此时A再更新MySQL就会出现不一致,可以使用延时双删来解决
        6. 通过回写来保证缓存的一致性,当缓存没有时会从数据库回写进入缓存
        7. 但如果删除缓存后正在更新MySQL但还未完成,此时访问数据就会读到MySQL中的旧数据,且还会把旧值写回缓存
      4. 先更新数据库再删除缓存
        1. 要保证MySQL为准,故必须先更新MySQL,然后删除缓存可以保证最终数据一致性
        2. 不可避免的会出现脏读,但要保证最终数据的一致性
        3. 此时会存在幻读,当MySQL还未更新时有线程读操作就会读到更新前的旧值
  4. 小总结
    1. 读取缓存使用双检加锁,更新数据时使用先更新数据库再删除缓存
    2. 缓存双写一致性,要保证最终数据一致性,当缓存数据不存在时使用双检加锁来从MySQL中回写入缓存中,读取缓存时要使用双检加锁,更新数据时要先更新数据库再删除缓存,此时读取读到不存在时使用双检加锁
    3. 更新数据时优先使用先更新数据库再删除缓存策略来保证缓存和数据库最终数据的一致性
    4. 如果使用先删除缓存再更新数据库,则要使用双删延迟,先删除缓存然后更新数据库,然后延迟一段时间后再删除缓存,此时延迟的时间不好估计,如果不使用双删延迟,则可能会导致最终不一致,因为更新完数据库后不会进行回写

3. 缓存双写一致性案例

  1. 复习与面试题
    1. 保证最终一致性,且以MySQL为准
    2. 更新时使用先更新数据库再删除缓存读取时使用双检加锁
    3. 如何将MySQL的改变同步反应到缓存中,使用canal中间件监听binlog日志去监控MySQL的改变,并在客户端实时写入Redis
  2. Canal:监听MySQL并通知Redis
    1. 是什么:基于MySQL数据库增量日志解析,提供增量数据订阅和消费
      1. 类似于Redis的AOF持久化,将MySQL的增量数据保存并发布给其他组件
      2. 基于MySQL数据库增量日志解析提供增量数据订阅和消费
    2. 工作原理
      1. MySQL主从复制原理,MySQL有一个binlog日志,记录增量
      2. Canal工作原理,基于MySQL增量日志解析,提供订阅和消费
    3. MySQL-canal-Redis双写一致性
      1. canal实时监控MySQL的更新,并同步给Redis,基于MySQL数据库增量日志解析,提供增量数据订阅和消费
      2. MySQL要开启binlog并配置canal账户
        1. 配置MySQL开启binlog二进制文件,并配置一个canal账户授予权限
        2. 开启MySQL的binlog写入功能,MySQL8默认开启
        3. 授权canal连接MySQL账号,默认MySQL中没有canal用户,此时要新建+授权
      3. Canal服务端
        1. 下载:在github上下载alibaba的canal开发版本
        2. 解压
        3. 配置
          1. 客户端会读取默认的配置文件,当设置了则进行覆盖
          2. 保证canal能够连接到MySQL的服务端,故要配置MySQL的IP和Port,并换成自己在MySQL上创建的canal用户
      4. Canal客户端
        使用Java编写canal客户端来监控MySQL数据库的变动并通知给Redis
        1. 建项目
        2. 改POM:要引入canal有关的依赖,去github的wiki操作文档
        3. 写YML
        4. 主启动
        5. 业务类
          1. RedisUtils
            1. 返回jedis连接的工具类,内部创建的jedis连接池,可以返回一个jedis连接
          2. RedisCanalClientExample
            1. 去github的官网上找example
            2. main中先创建canal连接,然后订阅指定库表的变动不要订阅全部库的全部表),然后获得MySQL中监听到的未确认的数据,如果为0说明没有数据改变,此时继续监听,如果不为0说明有数据变动,则打印printEntry获得的数据变动,然后对这些变动进行确认
            3. 在printEntry函数中,此时传入了数据变动的Entry,要对每个entry进行自定义的业务处理以及打印,for循环遍历所有的entry,然后判断每个变动的类型,根据类型调用相应的方法对Redis进行实现相应的操作,原始操作只是打印,如果要实现同步数据到Redis,要自己创建相应的函数来实现Redis数据的更新
          3. 通过canal客户端和服务端可以实现对MySQL数据库指定库表数据的实现监控,并得到变动的数据根据业务需求将变动数据更新到redis中,可以在canal客户端中编写相应的功能实现对Redis数据的一致性更新,相应操作根据业务需求自己编写
          4. 在main函数中获得canal连接后,要通过**connector.subscribe(“库.表(正则表达式)”)**订阅指定库表的变动,此时不要订阅所有的库表,否则会监控所有变动造成很大开销,也可以配置黑名单来指定不监控的库和表
          5. 当canal客户端某个配置未显式配置时,会自动读取配置文件中的配置,当配置了会覆盖配置文件中的配置,而默认是订阅所有的库和表
          6. try-with-resources释放资源,在try指令内的部分对象会自动关闭,不需要自己释放
      5. 小总结
        1. 通过使用canal中间件监控MySQL数据库的变动并实时回写进入Redis实现强一致性
        2. canal服务端会自动监听MySQL的数据变动,然后创建canal客户端来获得监听数据并回写到指定的Redis中

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日OJ题_牛客_相差不超过k的最多数_滑动窗口_C++_Java

目录 牛客_相差不超过k的最多数_滑动窗口 题目解析 C代码 Java代码 牛客_相差不超过k的最多数_滑动窗口 相差不超过k的最多数_牛客题霸_牛客网 (nowcoder.com) 描述: 给定一个数组,选择一些数,要求选择的数中任意两数差的绝对值不超过 …

初始JavaEE篇——多线程(5):生产者-消费者模型、阻塞队列

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏:JavaEE 文章目录 阻塞队列生产者—消费者模型生产者—消费者模型的优势:生产者—消费者模型的劣势: Java标准库中的阻…

后端eclipse——文字样式:UEditor富文本编辑器引入

目录 1.富文本编辑器的优点 2.文件的准备 3.文件的导入 导入到项目: 导入到html文件: ​编辑 4.富文本编辑器的使用 1.富文本编辑器的优点 我们从前端写入数据库时,文字的样式具有局限性,不能存在换行,更改字体…

Rust移动开发:Rust在Android端集成使用介绍

Andorid调用Rust 目前Rust在移动端上的应用,一般作为应用sdk的提供,供各端使用,目前飞书底层使用Rust编写通用组件。 该篇适合对Android、Rust了解,想看如何做整合,如果想要工程源码,可以评论或留言有解疑…

推荐一款高级的安装程序打包工具:Advanced Installer Architect

AdvanCEd Installer Architect是一款高级的安装程序打包工具,我们有时候可能用nsis用的多,Advanced Installer Architect也是一款打包工具,有兴趣的朋友也可以试试。有了Advanced Installer Architect你就可以创建MSI打包。 主要功能 *先进的…

关于Linux系统调试和性能优化技巧有哪些?

成长路上不孤单😊😊😊😊😊😊 【14后😊///C爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于Linux系统调试和性能优化技巧的相关内容…

MySQL中,GROUP BY 分组函数

文章目录 示例查询:按性别分组统计每组信息示例查询:按性别分组显示详细信息示例查询:按性别分组并计算平均年龄,如果你还想统计每个性别的平均年龄,可以结合AVG()函数:说明 示例查询:按性别分组统计每组信…

Docker:容器编排 Docker Compose

Docker:容器编排 Docker Compose docker-composedocker-compose.ymlservicesimagecommandenvironmentnetworksvolumesportshealthcheckdepends_on 命令docker compose updocker compose down其它 docker-compose 多数情况下,一个服务需要依赖多个服务&a…

.net Core 使用Panda.DynamicWebApi动态构造路由

我们以前是通过创建controller来创建API,通过controller来显示的生成路由,这里我们讲解下如何不通过controller,构造API路由 安装 Panda.DynamicWebApi 1.2.2 1.2.2 Swashbuckle.AspNetCore 6.2.3 6.2.3添加ServiceAction…

交换机如何实现2.5G网络传输速率和网络变压器有关吗

华强盛电子导读:I19926430038 交换机实现2.5G网络传输速率涉及多个因素,其中包括硬件设计、端口支持、传输介质以及网络协议等。网络变压器在其中扮演了一个重要的角色,但并不是唯一的因素。 1. **硬件设计**:交换机需要有支持2.…

Chrome 130 版本开发者工具(DevTools)更新内容

Chrome 130 版本开发者工具(DevTools)更新内容 一、网络(Network)面板更新 1. 重新定义网络过滤器 网络面板获新增了一些过滤条件,这些过滤条件是根据反馈重新设计的,特定于类型的过滤条件保持不变&…

JAVA设计模式之【建造者模式】

1 定义 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 2 类图 产品类(Product):表示被创建的复杂…

百度如何打造AI原生研发新范式?

👉点击即可下载《百度AI原生研发新范式实践》资料 2024年10月23-25日,2024 NJSD技术盛典暨第十届NJSD软件开发者大会、第八届IAS互联网架构大会在南京召开。本届大会邀请了工业界和学术界的专家,优秀的工程师和产品经理,以及其它行…

算法|牛客网华为机试31-40C++

牛客网华为机试 上篇:算法|牛客网华为机试21-30C 文章目录 HJ31 单词倒排HJ32 密码截取HJ33 整数与IP地址间的转换HJ34 图片整理HJ35 蛇形矩阵HJ36 字符串加密HJ37 统计每个月兔子的总数HJ38 求小球落地5次后所经历的路程和第5次反弹的高度HJ39 判断两个IP是否属于同…

UI自动化测试 —— CSS元素定位实践!

前言 自动化测试元素定位是指在自动化测试过程中,通过特定的方法或策略来准确识别和定位页面上的元素,以便对这些元素进行进一步的操作或断言。这些元素可以是文本框、按钮、链接、图片等HTML页面上的任何可见或不可见的组件。 在自动化测试中&#xf…

【实战篇】requests库 - 有道云翻译爬虫 【附:代理IP的使用】

目录 〇、引言一、目标二、请求参数分析三、响应分析四、编写爬虫脚本【隧道代理的使用】 〇、引言 无论是学习工作、旅游出行、跨境电商、日常交流以及一些专业领域都离不开翻译工具的支持。本文就带大家通过爬虫的方式开发一款属于自己的翻译工具~ 一、目标 如下的翻译接口…

Spring框架的声明式事务

目录 一.配置文件的方式 1.配置文件 2.业务层 3.持久层 4.测试类 5.运行 6.查看数据库 7.出现异常运行 二.半注解的方式 1.配置文件 2.db.properties 3.持久层 4.业务层 5.测试类 6.运行 7.查看数据库 8.加上异常 三.纯注解的方式 1.持久层 2.业务层 3.配置…

电脑开机显示无信号然后黑屏怎么办?

当我们打开电脑时,遇到电脑屏幕出现了无信号并且黑屏,常常会让我们感到困扰。很多朋友都会遇到显示器无信号的情况,其实这种故障是很好解决的,但是电脑小白,并不知道电脑屏幕显示无信号然后黑屏了要怎么去修复。不用担…

Ubuntu-22.04 虚拟机安装

1. Ubuntu安装方式 1.1. 基于物理介质安装 光盘安装:通过将 Ubuntu 镜像刻录到光盘,在计算机 BIOS/UEFI 中设置光盘为第一启动项,然后按照安装程序的提示进行语言选择、分区、用户信息设置等操作来完成安装。这种方式需要有光盘刻录设备和空…

51c~Pytorch~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/12320861 一、pytorch开发基础相关 首先 PyTorch 的安装可以根据官方文档进行操作:(根据自己cuda版本不同 安装版本也不太一样啊 自己注意) ​​https://pytorch.org/​​ pip install…