Redis学习【12】之Redis 缓存

news2024/11/29 11:49:35

文章目录

  • 前言
  • 一 Jedis 简介
  • 二 使用 Jedis
    • 2.1 测试代码
    • 2.2 使用 JedisPool
    • 2.3 使用 JedisPooled
    • 2.4 连接 Sentinel 高可用集群
    • 2.5 连接分布式系统
    • 2.6 操作事务
  • 三 Spring Boot整合Redis
    • 3.1 创建工程
    • 3.2 定义 pom 文件
    • 3.3 完整代码
    • 3.4 总结
  • 四 高并发问题
    • 4.1 缓存穿透
    • 4.2 缓存击穿
    • 4.3 缓存雪崩
    • 4.5 数据库缓存双写不一致
      • 4.5.1 “修改 DB 更新缓存”场景
      • 4.5.2 “修改 DB 删除缓存”场景
      • 4.5.3 解决方案:延迟双删
      • 4.5.4 解决方案:队列
      • 4.5.4 解决方案:分布式锁

前言

  • 本文是作者在学习redis的笔记,学习动力节点的redis课程
  • 仅供学习交流,不得用于商业用途

一 Jedis 简介

  • Jedis 是一个基于 java 的 Redis 客户端连接工具,旨在提升性能与易用性。github 上的官网地址

二 使用 Jedis

  • Jedis 基本使用十分简单,其提供了非常丰富的操作 Redis 的方法,而这些方法名几乎与Redis 命令相同。
  • 在每次使用时直接创建 Jedis 实例即可。在 Jedis 实例创建好之后,Jedis 底层实际会创建一个到指定 Redis 服务器的 Socket 连接。所以,为了节省系统资源与网络带宽,在每次使用完 Jedis 实例之后,需要立即调用 close()方法将连接关闭。
  • 首先创建一个普通的 Maven 工程 ,然后在 POM 文件中添加 Jedis 与 Junit 依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.2.0</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.25</version>
    <scope>test</scope>
</dependency>

2.1 测试代码

import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.resps.Tuple;

import java.util.HashMap;
import java.util.List;
import java.util.Set;


/**
 * @author 缘友一世
 * date 2023/3/8-22:44
 */
public class test {
    /**
     * value 为 String 的测试
     */
    @Test
    public void test01() {
        Jedis jedis = new Jedis("192.168.28.123", 6379);
        jedis.set("name","007");
        jedis.mset("age","23","depart","market");
        System.out.println(jedis.get("name"));
        System.out.println(jedis.get("age"));
        System.out.println(jedis.get("depart"));
        jedis.close();
    }

    /**
     * value 为 Hash 的测试
     */
    @Test
    public void test02() {
        Jedis jedis = new Jedis("192.168.28.123", 6379);
        jedis.hset("direction","east","north");
        HashMap<String, String> map = new HashMap<>();
        map.put("height","500m");
        map.put("character","major");
        jedis.hset("mapTest",map);
        String heigt = jedis.hget("mapTest", "height");
        List<String> mapTest = jedis.hmget("mapTest", "height", "character");
        System.out.println("height:"+heigt);
        System.out.println("mapTest:"+mapTest);
        jedis.close();
    }

    /**
     * value 为 List 的测试
     */
    @Test
    public void test03() {
        Jedis jedis = new Jedis("192.168.28.123", 6379);
        jedis.rpush("cities","冰雪北境","南幻水乡","西凉荒漠");
        List<String> cities = jedis.lrange("cities", 0, -1);
        System.out.println("cities:"+cities);
        jedis.close();
    }

    /**
     * value 为 Set 的测试
     */
    @Test
    public void test04() {
        Jedis jedis = new Jedis("192.168.28.123", 6379);
        long sadd = jedis.sadd("midwares", "Redi", "Nginx", "RocketMQ");
        Set<String> midwares = jedis.smembers("midwares");
        System.out.println("midwares:"+midwares);
        jedis.close();
    }

    /**
     * value 为 zSet 的测试
     */
    @Test
    public void test05() {
        Jedis jedis = new Jedis("192.168.28.123", 6379);
        jedis.zadd("sales",80,"BMW");
        jedis.zadd("sales",90,"BYD");
        jedis.zadd("sales",60,"Benz");
        jedis.zadd("sales",70,"BMW");
        //获取销量前三
        List<String> top = jedis.zrevrange("sales", 0, 2);
        System.out.println("top:"+top);
        List<Tuple> sales = jedis.zrevrangeWithScores("sales", 0, -1);
        for (Tuple sale:sales) {
            System.out.println(sale.getScore()+":"+sale.getElement());
        }
        jedis.close();
    }
}

2.2 使用 JedisPool

  • 如果应用非常频繁地创建和销毁 Jedis 实例,虽然节省了系统资源与网络带宽,但会大大降低系统性能。因为创建和销毁 Socket 连接是比较耗时的。此时可以使用 Jedis 连接池来解决该问题。
  • 使用 JedisPool 与使用 Jedis 实例的区别是,JedisPool 是全局性的,整个类只需创建一次即可,然后每次需要操作 Redis 时,只需从 JedisPool 中拿出一个 Jedis 实例直接使用即可。使用完毕后,无需释放 Jedis 实例,只需返回 JedisPool 即可。
/**
 * @author 缘友一世
 * date 2023/3/8-23:12
 */
public class jedisPool {

    @Test
    public void test01(){
        JedisPool jedisPool = new JedisPool("192.168.28.123", 6379);
        try(Jedis jedis=jedisPool.getResource()) {
            jedis.set("name","007");
            jedis.mset("age","23","depart","market");
            System.out.println("name:"+jedis.get("name"));
            System.out.println("age"+jedis.get("age"));
            System.out.println("depart"+jedis.get("depart"));
        }
    }
}

2.3 使用 JedisPooled

  • 对于每次对 Redis 的操作都需要使用 try-with-resource 块是比较麻烦的,而使用JedisPooled 则无需再使用该结构来自动释放资源
/**
 * 使用JedisPooled 则无需再使用该结构来自动释放资源
 */
@Test
public void test02(){
    JedisPooled jedisPooled = new JedisPooled("192.168.28.123", 6379);
    //value为string的情况
    jedisPooled.set("id","212666");
    jedisPooled.mset("tools","weChat","search","everything");
    System.out.println("id:"+jedisPooled.get("id"));
    System.out.println("tools:"+jedisPooled.get("tools"));
    System.out.println("search:"+jedisPooled.get("search"));
}

2.4 连接 Sentinel 高可用集群

  • 对于 Sentinel 高可用集群的连接,直接使用 JedisSentinelPool 即可。在该客户端只需注册所有 Sentinel 节点及其监控的 Master 的名称即可,无需出现 master-slave 的任何地址信息。
  • 其采用的也是 JedisPool,使用完毕的 Jedis 也需要通过 close()方法将其返回给连接池。
/**
 * @author 缘友一世
 * date 2023/3/9-9:20
 */
public class jedisSentinelPoolTest {
    private JedisSentinelPool jedisPool;
    {
        Set<String> sentinels = new HashSet<>();
        sentinels.add("192.168.28.123:26380");
        sentinels.add("192.168.28.123:26381");
        sentinels.add("192.168.28.123:26382");
        jedisPool = new JedisSentinelPool("mymaster", sentinels);
    }
    @Test
    public void test01(){
        try(Jedis jedis=jedisPool.getResource()) {
            jedis.set("math","100");
            jedis.mset("math2","100","age2","18");
            System.out.println("math:"+jedis.get("math"));
            System.out.println("math2:"+jedis.get("math2"));
            System.out.println("age2:"+jedis.get("age2"));
        }
    }
    @Test
    public void test() {
        Jedis jedis = new Jedis("192.168.28.123", 6380);
        System.out.println(jedis.get("name"));
    }
}

2.5 连接分布式系统

  • 对于 Redis 的分布式系统的连接,直接使用 JedisCluster 即可。其底层采用的也是 Jedis连接池技术。每次使用完毕后,无需显式关闭,其会自动关闭。
  • 对于 JedisCluster 常用的构造器有两个:
    • 一个是只需一个集群节点的构造器,这个节点可以是集群中的任意节点,只要连接上了该节点,就连接上了整个集群。但该构造器存在一个风险:其指定的这个节点在连接之前恰好宕机,那么该客户端将无法连接上集群。
    • 所以,推荐使用第二个构造器,即将集群中所有节点全部罗列出来。这样就会避免这种风险
/**
 * @author 缘友一世
 * date 2023/3/9-12:29
 */
public class jedisClusterTest {
    private JedisCluster jedisCluster;
    {
        HashSet<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.168.28.123",6380));
        nodes.add(new HostAndPort("192.168.28.123",6381));
        nodes.add(new HostAndPort("192.168.28.123",6382));
        nodes.add(new HostAndPort("192.168.28.123",6383));
        nodes.add(new HostAndPort("192.168.28.123",6384));
        nodes.add(new HostAndPort("192.168.28.123",6385));
        jedisCluster=new JedisCluster(nodes);
    }
    @Test
    public void test01(){

        jedisCluster.set("name","wuwang");
        System.out.println("name:"+jedisCluster.get("name"));
    }
}

2.6 操作事务

  • 对于 Redis 事务的操作,Jedis 提供了 multi()、watch()、unwatch()方法来对应 Redis 中的multi、watch、unwatch 命令。Jedis的 multi()方法返回一个 Transaction 对象,其 exec()与 discard()方法用于执行和取消事务的执行
/**
 * @author 缘友一世
 * date 2023/3/9-23:04
 */
public class jedisTxTest {
    public static void main(String[] args) {
        JedisPool jedisPool = new JedisPool("192.168.28.123", 6379);
        try(Jedis jedis=jedisPool.getResource()) {
            jedis.set("name","001");
            //构造异常
            Transaction multi = jedis.multi();
            try {
                int i=1/0;
                multi.set("name","002");
                multi.exec();
            }catch (Exception e) {
                //发生异常全部,回滚
                multi.discard();
            }finally {
                System.out.println(jedis.get("name"));
            }
        }
    }
}

三 Spring Boot整合Redis

  • 下面通过一个例子来说明 Spring Boot 是如何与 Redis 进行整合的。
    • 对于一个资深成熟的金融产品交易平台,其用户端首页一般会展示其最新金融产品列表,同时还为用户提供了产品查询功能。另外,为了显示平台的实力与信誉,在平台首页非常显眼的位置还会展示平台已完成的总交易额与注册用户数量。对于管理端,管理员可通过管理
      页面修改产品、上架新产品、下架老产品。
    • 为了方便了解 Redis 与 Spring Boot 的整合流程,这里对系统进行了简化:用户端首页仅提供根据金融产品名称的查询,显眼位置仅展示交易总额。管理端仅实现上架新产品功能。

3.1 创建工程

  • 定义一个 Spring Boot 工程

3.2 定义 pom 文件

  • 在 pom 文件中需要导入 MySQL 驱动、Druid 等大量依赖
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(20) DEFAULT NULL,
 `rate` double DEFAULT NULL,
 `amount` double DEFAULT NULL,
 `raised` double DEFAULT NULL,
 `cycle` int(11) DEFAULT NULL,
 `endTime` char(10) DEFAULT '0',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

INSERT INTO `product` VALUES 
(1,'天鑫添益 2',2.76,50000,20000,30,'2022-07-10'),
(2,'国泰添益',2.86,30000,30000,60,'2022-07-12'),
(3,'国泰高鑫',2.55,60000,50000,90,'2022-07-09'),
(4,'国福民安',2.96,30000,20000,7,'2022-05-10'),
(5,'天益鑫多',2.65,80000,60000,20,'2022-07-05'),
(6,'惠农收益',3.05,30000,20000,10,'2022-06-10'),
(7,'惠农三鑫',2.76,50000,30000,30,'2022-07-02'),
(8,'励学收益',2.86,30000,20000,20,'2022-07-11');

3.3 完整代码

  • 项目源码地址
  • 源码的内容,自动力节点案例的改进【主要解决:打开主页面,直接卸载jsp文件的错误】
  • 这里作者遇到了打开jsp主页,直接下载了jsp文件。可能的原因是浏览器配置了NDM多线程下载器

3.4 总结

  • 如何将 Spring Boot 与 Redis 整合?
    • 在 POM 中导入依赖
    • 在配置文件中注册 Redis 连接信息与缓存信息
    • 需要缓存到 Redis 中的实体类必须要序列化
    • Spring Boot 启动类中要添加@EnableCaching 注解
    • 查询方法上要添加@Cacheable 注解
    • 对数据进行写操作的方法上添加@CacheEvict 注解
    • 对于需要手工操作 Redis 的方法,需通过 RedisTemplate 来获取操作对象

四 高并发问题

  • Redis 做缓存虽减轻了 DBMS 的压力,减小了 RT,但在高并发情况下也是可能会出现各种问题的。

4.1 缓存穿透

  • 当用户访问的数据既不在缓存也不在数据库中时,就会导致每个用户查询都会“穿透”缓存“直抵”数据库。这种情况就称为缓存穿透。当高度发的访问请求到达时,缓存穿透不仅增加了响应时间,而且还会引发对 DBMS 的高并发查询,这种高并发查询很可能会导致DBMS 的崩溃。
  • 缓存穿透产生的主要原因有两个:一是在数据库中没有相应的查询结果,二是查询结果为空时,不对查询结果进行缓存。所以,针对以上两点,解决方案也有两个:
    • 对非法请求进行限制
    • 对结果为空的查询给出默认值

4.2 缓存击穿

  • 对于某一个缓存,在高并发情况下若其访问量特别巨大,当该缓存的有效时限到达时,可能会出现大量的访问都要重建该缓存,即这些访问请求发现缓存中没有该数据,则立即到DBMS 中进行查询,那么这就有可能会引发对 DBMS 的高并发查询,从而接导致 DBMS 的崩溃。这种情况称为缓存击穿,而该缓存数据称为热点数据。
  • 对于缓存击穿的解决方案,较典型的是使用“双重检测锁”机制。

4.3 缓存雪崩

  • 对于缓存中的数据,很多都是有过期时间的。若大量缓存的过期时间在同一很短的时间段内几乎同时到达,那么在高并发访问场景下就可能会引发对 DBMS 的高并发查询,而这将可能直接导致 DBMS 的崩溃。这种情况称为缓存雪崩。
  • 对于缓存雪崩没有很直接的解决方案,最好的解决方案就是预防,即提前规划好缓存的过期时间。要么就是让缓存永久有效,当 DB 中数据发生变化时清除相应的缓存。如果 DBMS采用的是分布式部署,则将热点数据均匀分布在不同数据库节点中,将可能到来的访问负载
    均衡开来。

4.5 数据库缓存双写不一致

  • 以上三种情况都是针对高并发读场景中可能会出现的问题,而数据库缓存双写不一致问题,则是在高并发写场景下可能会出现的问题。
    对于数据库缓存双写不一致问题,以下两种场景下均有可能会发生:

4.5.1 “修改 DB 更新缓存”场景

  • 对于具有缓存 warmup 功能的系统,DBMS 中常用数据的变更,都会引发缓存中相关数据的更新。在高并发写请求场景下,若多个请求要对 DBMS 中同一个数据进行修改,修改后还需要更新缓存中相关数据,那么就有可能会出现缓存与数据库中数据不一致的情况。
    在这里插入图片描述

4.5.2 “修改 DB 删除缓存”场景

  • 在很多系统中是没有缓存 warmup 功能的,为了保持缓存与数据库数据的一致性,一般都是在对数据库执行了写操作后,就会删除相应缓存。
  • 在高并发读写请求场景下,若这些请求对 DBMS 中同一个数据的操作既包含写也包含读,且修改后还要删除缓存中相关数据,那么就有可能会出现缓存与数据库中数据不一致的情况
    在这里插入图片描述

4.5.3 解决方案:延迟双删

  • 延迟双删方案是专门针对于“修改 DB 删除缓存”场景的解决方案。但该方案并不能彻底解决数据不一致的状况,其只可能降低发生数据不一致的概率。
  • 延迟双删方案是指,在写操作完毕后会立即执行一次缓存的删除操作,然后再停上一段时间(一般为几秒)后再进行一次删除。而两次删除中间的间隔时长,要大于一次缓存写操作的时长。
    在这里插入图片描述

4.5.4 解决方案:队列

  • 以上两种场景中,只所以会出现数据库与缓存中数据不一致,主要是因为对请求的处理出现了并行。只要将请求写入到一个统一的队列,只有处理完一个请求后才可处理下一个请求,即使系统对用户请求的处理串行化,就可以完全解决数据不一致的问题。

4.5.4 解决方案:分布式锁

  • 使用队列的串行化虽然可以解决数据库与缓存中数据不一致,但系统失去了并发性,降低了性能。使用分布式锁可以在不影响并发性的前提下,协调各处理线程间的关系,使数据库与缓存中的数据达成一致性。
  • 只需要对数据库中的这个共享数据的访问通过分布式锁来协调对其的操作访问即可。

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

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

相关文章

全方位解读智能中控屏发展趋势!亚马逊Alexa语音+Matter能力成必备

随着智能家居行业逐步从碎片化的智能单品阶段&#xff0c;迈向体验更完整的全屋互联阶段&#xff0c;智能中控屏作为智能家居最佳的入口之一&#xff0c;在年轻人青睐全屋智能装修的风潮下&#xff0c;市场潜力彻底被引爆。 一、为什么是智能中控屏&#xff1f; 在智能音箱增…

诗一样的代码命名规范

有文化&#xff1a;落霞与孤鹜齐飞&#xff0c;秋水共长天一色&#xff1b;没文化&#xff1a;太阳落山的时候&#xff0c;看见一只鸟在水上飞&#xff1b;日常编码中&#xff0c;代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图&#xff0c;也是一项必备的能力…

Docker入门建议收藏 第二部分

二、Docker 容器技术与虚拟机的区别 Docker 到底是个什么东西呢&#xff1f;我们在理解 Docker 之前&#xff0c;首先得先区分清楚两个概念&#xff0c;容器和虚拟机。 虚拟机 虚拟机&#xff08;Virtual Machine&#xff09;指通过软件模拟的具有完整硬件系统功能的、运行在…

单链表的头插,尾插,头删,尾删等操作

前言顺序表要求是具有连续的物理空间&#xff0c;并且数据的话是在这些空间当中是连续的存储。但这样会带来很多问题&#xff0c;比如说在头部或者说中间插入的话&#xff0c;效率不是很高&#xff1b;并且申请空间可能需要扩容&#xff0c;并且越往后一般来说都是异地扩容&…

优思学院|精益生产中的“单件流”真的能够做到吗?

精益生产中提到的“一个流”&#xff08;One Piece Flow&#xff09;是一种生产方式&#xff0c;它的核心理念是通过合理配置作业场地、人员和设备&#xff0c;使产品从投入到成品产出的整个制造加工过程中始终处于不停滞、不堆积、不超越&#xff0c;按节拍一个一个地流动。 …

Idea+maven+spring-cloud项目搭建系列--11 整合dubbo

前言&#xff1a; 微服务之间通信框架dubbo&#xff0c;使用netty &#xff08;NIO 模型&#xff09;完成RPC 接口调用&#xff1b; 1 dubbo 介绍&#xff1a; Apache Dubbo 是一款 RPC 服务开发框架&#xff0c;用于解决微服务架构下的服务治理与通信问题&#xff0c;官方提…

渲染十万条数据就把你难住了?不存在的!

虚拟列表的使用场景如果我想要在网页中放大量的列表项&#xff0c;纯渲染的话&#xff0c;对于浏览器性能将会是个极大的挑战&#xff0c;会造成滚动卡顿&#xff0c;整体体验非常不好&#xff0c;主要有以下问题&#xff1a;页面等待时间极长&#xff0c;用户体验差CPU计算能力…

pyqt5(二) 标签(QLabel)组件的属性说明及示例

使用语法 widget QLable() widget.function(parameter) widget&#xff1a;实例化QLablefunction&#xff1a;QLable里的函数parameter&#xff1a;函数需要用到的参数 参数说明&#xff1a; 参数说明参数解释 setText() 配置文本内容 setPixmap() 添加图片 setFixedSize(…

蓝桥杯--等差素数列

等差素数列 技巧 这里的等差数列–首项需要枚举列出 公差也需要枚举列出 在公差为1开始&#xff0c;对n-1也进行枚举 //重要代码段 判断一个数是否为素数 int check(int n) { for(int i2;i<n;i){if(n%i0){return 0 } return 1; } }这道题不是很简单 本题为填空题&#xff0…

Webstorm使用、nginx启动、FinalShell使用

文章目录 主题设置FinalShellFinalShell nginx 启动历史命令Nginx页面发布配置Webstorm的一些常用快捷键代码生成字体大小修改Webstorm - gitCode 代码拉取webstorm 汉化webstorm导致CPU占用率高方法一 【忽略node_modules】方法二 【设置 - 代码编辑 - 快速预览文档 - 关闭】主…

Linux 练习七 (IPC 共享内存)

文章目录System V 共享内存机制&#xff1a;shmget shmat shmdt shmctl案例一&#xff1a;有亲缘关系的进程通信案例二&#xff1a;非亲缘关系的进程通信内存写端write1.c内存读端read1.c案例三&#xff1a;不同程序之间的进程通信程序一&#xff0c;写者shmwr.c程序二&#xf…

2022-06-14至2022-08-11 关于复现MKP算法的总结与反思

Prerequisite 自2022年6月14日至2022年8月11日的时间内&#xff0c;我致力于完成A Hybrid Approach for the 0–1 Multidimensional Knapsack problem 论文的复现工作&#xff0c;此次是我第一次进行组合优化方向的学习工作&#xff0c;下面介绍该工作内容发展过程以及该工作结…

JavaScript Array 数组对象实例集合

文章目录JavaScript Array 数组对象实例集合创建数组合并两个数组 - concat()合并三个数组 - concat()用数组的元素组成字符串 - join()删除数组的最后一个元素 - pop()数组的末尾添加新的元素 - push()反转一个数组中的元素的顺序 - reverse()删除数组的第一个元素 - shift()从…

数字化时代,企业的商业模式建设

随着新一代信息化、数字化技术的应用&#xff0c;众多领域通过科技革命和产业革命实现了深度化的数字改造&#xff0c;进入到以数据为核心驱动力的&#xff0c;全新的数据处理时代&#xff0c;并通过业务系统、商业智能BI等数字化技术和应用实现了数据价值&#xff0c;从数字经…

Vue项目打包部署总结配合nginx部署

你可能还想了解&#xff1a;https://blog.csdn.net/weixin_52901235/article/details/129437990?spm1001.2014.3001.5502使用Vue做前后端分离项目时&#xff0c;通常前端是单独部署&#xff0c;用户访问的也是前端项目地址&#xff0c;因此前端开发人员很有必要熟悉一下项目部…

C#要点技术(二) - Dictionary 底层源码剖析

Dictionary 底层代码我们知道 Dictionary 字典型数据结构&#xff0c;是以关键字Key 和 值Value 进行一一映射的。Key的类型并没有做任何的限制&#xff0c;可以是整数&#xff0c;也可以是的字符串&#xff0c;甚至可以是实例对象。关键字Key是如何映射到内存的呢&#xff1f;…

【python】如何用python写一个下拉选择框和页签?

文章目录前言ttk模块下拉选择框combobox下拉选择框2页签Notebook前言 python学习之路任重而道远&#xff0c;要想学完说容易也容易&#xff0c;说难也难。 很多人说python最好学了&#xff0c;但扪心自问&#xff0c;你会用python做什么了&#xff1f; 刚开始在大学学习c语言&…

【玩转c++】stack和queue的介绍和模拟实现

本期主题&#xff1a;list的讲解和模拟实现博客主页&#xff1a; 小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限&#xff0c;出现错误希望大家不吝赐stack的介绍和使用1.1.stack的介绍1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上…

论文阅读-MGTAB: A Multi-Relational Graph-Based Twitter Account DetectionBenchmark

目录 摘要 1. 引言 2. 相关工作 2.1. 立场检测 2.2.机器人检测 3.数据集预处理 3.1.数据收集和清理 3.2.专家注释 3.3. 质量评估 3.4.特征分析 4. 数据集构建 4.1.特征表示构造 4.2.关系图构建 5. 实验 5.1.实验设置 5.2.基准性能 5.3训练集大小的研究 5.4 社…

Matlab进阶绘图第6期—雷达图/蜘蛛图/星图

雷达图&#xff08;Radar Chart&#xff09;&#xff0c;又称星图、蜘蛛图、蜘蛛网图、网络图、Kiviat图等&#xff0c;是一种以从同一点开始的轴上表示的三个以上变量的二维图表的形式&#xff0c;来显示多变量数据的图形方法。 雷达图可以直观地对多维数据集目标对象的性能、…