Redis 常用数据类型插入性能对比:循环插入 vs. 批量插入

Redis 是一款高性能的键值数据库,其支持多种数据类型(String、Hash、List、Set、ZSet、Geo)。在开发中,经常会遇到需要插入大量数据的场景。如果逐条插入,性能会显得较低,而采用 Pipeline 批量插入 能大幅提升插入效率。本文将基于常见的 Redis 数据类型,对比循环插入与批量插入的性能差异。 以下测试结果仅供参考,真实环境请多测试! 


1. 测试环境说明

  • Redis 版本:3.x、5.x 或更高
  • Spring Boot 环境spring-boot-starter-data-redis

测试过程中,我们将模拟插入 1 万 / 10 万条数据,并记录执行时间。以下是常见的 Redis 数据类型及其插入方法。


2. 各数据类型的插入实现

2.1 String 类型
  • 循环插入:

逐条使用 opsForValue().set() 方法进行插入:

    /**
     * String类型测试循环插入性能
     * @param dataCount
     */
    public void testInsertPerformanceStr(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForValue().set(StrKey+i, "value" + i);
        }
        log.info("使用String类型循环插入{}条数据,总耗时为: {} ms",dataCount, System.currentTimeMillis() - beginTime);

    }

  • 批量插入:

通过 Redis Pipeline 批量操作提升性能:

    /**
     * String类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedStr(int dataCount) {
        // 开始计时
        long startTime = System.currentTimeMillis();

        // 使用 Redis Pipeline 进行批量插入
        stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (int i = 0; i < dataCount; i++) {
                // 构造键值对
                String key = StrKey + i;
                String value = "value" + i;

                // 将命令加入 pipeline
                connection.stringCommands().set(key.getBytes(), value.getBytes());
            }
            return null;
        });

        // 结束计时
        long elapsedTime = System.currentTimeMillis() - startTime;

        log.info("使用String类型批量插入{}条数据,总耗时为: {}ms", dataCount, elapsedTime);
         使用 Lua 脚本删除匹配的键
        //String luaScript = "local keys = redis.call('keys', ARGV[1]) " +
        //        "for i, key in ipairs(keys) do " +
        //        "redis.call('del', key) " +
        //        "end " +
        //        "return #keys";
        //DefaultRedisScript<Long> script = new DefaultRedisScript<>(luaScript, Long.class);
        //Long deletedKeysCount = redisTemplate.execute(script, Collections.emptyList(), StrKey + "*");
        //
        //log.info("成功删除前缀为 {} 的所有键,共删除 {} 个键", StrKey, deletedKeysCount);

    }

性能对比
插入方式插入数据量耗时(ms)
循环插入1万条500+
批量插入1 万条150+

2.2 ZSet(有序集合)类型
  • 循环插入:
    /**
     * ZSet测试循环插入性能
     *
     * @param dataCount
     */
    public void testInsertPerformanceZSet(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForZSet().add(ZSetKey, "value" + i, i);
        }
        log.info("使用ZSet类型循环插入{}条数据,总耗时为: {} ms", dataCount, System.currentTimeMillis() - beginTime);

    }

  • 批量插入:

使用 opsForZSet().add() 的批量插入方法:

    /**
     * ZSet测试批量处理插入性能
     *
     * @param dataCount
     */
    public void testBatchInsertOptimizedZSet(int dataCount) {
        // 开始计时
        long startTime = System.currentTimeMillis();

        HashSet<ZSetOperations.TypedTuple<String>> redisBatchData = new HashSet<>();
        for (int i = 0; i < dataCount; i++) {
            redisBatchData.add(ZSetOperations.TypedTuple.of("value" + i, (double) i));
        }
        // 一次性批量插入
        stringRedisTemplate.opsForZSet().add(ZSetKey, redisBatchData);

        log.info("使用ZSet类型批量插入{}条数据,总耗时:{}ms ", dataCount, (System.currentTimeMillis() - startTime));
    }

性能对比
插入方式插入数据量耗时(ms)
循环插入1 万条660+
批量插入1 万条50+

2.3 Hash 类型
  • 循环插入:
    /**
     * Hash类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceHash(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForHash().put(HashKey, "key" + i, "value" + i);
        }
        log.info("使用Hash类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }
  • 批量插入:
    /**
     * Hash类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedHash(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 构造批量数据
        Map<String, String> hashData = IntStream.range(0, dataCount)
                .boxed()
                .collect(Collectors.toMap(i -> "key" + i, i -> "value" + i));

        // 批量插入
        stringRedisTemplate.opsForHash().putAll(HashKey, hashData);

        log.info("使用Hash类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }

性能对比
插入方式插入数据量耗时(ms)
循环插入1 万条450+
批量插入1 万条15+

2.4 Set 类型
  • 循环插入:
    /**
     * Set类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceSet(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForSet().add("lps::test_set", "value" + i);
        }
        log.info("使用Set类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }
  • 批量插入:
    /**
     * Set类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedSet(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 批量插入
        stringRedisTemplate.opsForSet().add("lps::test_set", Arrays.toString(IntStream.range(0, dataCount)
                .mapToObj(i -> "value" + i).distinct().toArray()));

        log.info("使用Set类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }

性能对比
插入方式插入数据量耗时(ms)
循环插入1 万条430+
批量插入1 万条2+

2.5 Geo 类型
  • 循环插入:
    /**
     * Geo类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceGeo(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForGeo().add("lps::test_geo", generateValidPoint(i), "location" + i);
        }
        log.info("使用Geo类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }

        /**
     * 生成合法的 Geo 数据点
     */
    private Point generateValidPoint(int index) {
        // 生成经度 [-180, 180]
        double longitude = (index % 360) - 180;

        // 生成纬度 [-85.05112878, 85.05112878]
        double latitude = ((index % 170) - 85) * 0.1;

        return new Point(longitude, latitude);
    }

  • 批量插入:
    /**
     * Geo类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedGeo(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 构造批量数据
        List<RedisGeoCommands.GeoLocation<String>> geoLocations = IntStream.range(0, dataCount)
                .mapToObj(i -> new RedisGeoCommands.GeoLocation<>("location" + i,
                        generateValidPoint(i)))
                .collect(Collectors.toList());

        // 批量插入
        stringRedisTemplate.opsForGeo().add("lps::test_geo", geoLocations);

        log.info("使用Geo类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }

        /**
     * 生成合法的 Geo 数据点
     */
    private Point generateValidPoint(int index) {
        // 生成经度 [-180, 180]
        double longitude = (index % 360) - 180;

        // 生成纬度 [-85.05112878, 85.05112878]
        double latitude = ((index % 170) - 85) * 0.1;

        return new Point(longitude, latitude);
    }
性能对比
插入方式插入数据量耗时(ms)
循环插入1 万条496+
批量插入1 万条27+

 2.6 List 类型
  • 循环插入:
    /**
     * List类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceList(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForList().rightPush(ListKey, "value" + i);
        }
        log.info("使用List类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }

  • 批量插入:
    /**
     * List类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedList(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 构造批量数据
        List<String> values = IntStream.range(0, dataCount)
                .mapToObj(i -> "value" + i)
                .collect(Collectors.toList());

        // 批量插入
        stringRedisTemplate.opsForList().rightPushAll(ListKey, values);

        log.info("使用List类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }
性能对比
插入方式插入数据量耗时(ms)
循环插入1 万条429+
批量插入1 万条8+

3. 执行图片

5.0.14.1版本 - 1w数据插入

5.0.14.1版本 - 10w数据插入

3.2.100版本 - 1w数据插入

3.2.100版本 - 10w数据插入

4. 完整类如下


@Service
@Slf4j
public class RedisServiceImpl implements RedisService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    public static final String ZSetKey = "lps::test_zset";
    public static final String StrKey = "lps::test_str::";
    public static final String ListKey = "lps::test_list";
    public static final String HashKey = "lps::test_hash";

    @Override
    public void runInsert(int number) {
        checkVersion();

        //ZSet类型
        testInsertPerformanceZSet(number);
        testBatchInsertOptimizedZSet(number);

        //String类型
        testInsertPerformanceStr(number);
        testBatchInsertOptimizedStr(number);

        //List类型
        testInsertPerformanceList(number);
        testBatchInsertOptimizedList(number);

        //Hash类型
        testInsertPerformanceHash(number);
        testBatchInsertOptimizedHash(number);

        //Set类型
        testInsertPerformanceSet(number);
        testBatchInsertOptimizedSet(number);

        //Geo类型
        testInsertPerformanceGeo(number);
        testBatchInsertOptimizedGeo(number);

    }

    public void checkVersion() {
        RedisConnection connection = Objects.requireNonNull(stringRedisTemplate.getConnectionFactory()).getConnection();
        String redisVersion = String.valueOf(Objects.requireNonNull(connection.info("server")).get("redis_version"));
        log.info("本台机器的Redis 版本为:{}", redisVersion);
    }

    /**
     * ZSet测试循环插入性能
     *
     * @param dataCount
     */
    public void testInsertPerformanceZSet(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForZSet().add(ZSetKey, "value" + i, i);
        }
        log.info("使用ZSet类型循环插入{}条数据,总耗时为: {} ms", dataCount, System.currentTimeMillis() - beginTime);

    }

    /**
     * ZSet测试批量处理插入性能
     *
     * @param dataCount
     */
    public void testBatchInsertOptimizedZSet(int dataCount) {
        // 开始计时
        long startTime = System.currentTimeMillis();

        HashSet<ZSetOperations.TypedTuple<String>> redisBatchData = new HashSet<>();
        for (int i = 0; i < dataCount; i++) {
            redisBatchData.add(ZSetOperations.TypedTuple.of("value" + i, (double) i));
        }
        // 一次性批量插入
        stringRedisTemplate.opsForZSet().add(ZSetKey, redisBatchData);

        log.info("使用ZSet类型批量插入{}条数据,总耗时:{}ms ", dataCount, (System.currentTimeMillis() - startTime));
    }

    /**
     * String类型测试循环插入性能
     *
     * @param dataCount
     */
    public void testInsertPerformanceStr(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForValue().set(StrKey + i, "value" + i);
        }
        log.info("使用String类型循环插入{}条数据,总耗时为: {} ms", dataCount, System.currentTimeMillis() - beginTime);

    }

    /**
     * String类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedStr(int dataCount) {
        // 开始计时
        long startTime = System.currentTimeMillis();

        // 使用 Redis Pipeline 进行批量插入
        stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (int i = 0; i < dataCount; i++) {
                // 构造键值对
                String key = StrKey + i;
                String value = "value" + i;

                // 将命令加入 pipeline
                connection.stringCommands().set(key.getBytes(), value.getBytes());
            }
            return null;
        });

        // 结束计时
        long elapsedTime = System.currentTimeMillis() - startTime;

        log.info("使用String类型批量插入{}条数据,总耗时为: {}ms", dataCount, elapsedTime);
         使用 Lua 脚本删除匹配的键
        //String luaScript = "local keys = redis.call('keys', ARGV[1]) " +
        //        "for i, key in ipairs(keys) do " +
        //        "redis.call('del', key) " +
        //        "end " +
        //        "return #keys";
        //DefaultRedisScript<Long> script = new DefaultRedisScript<>(luaScript, Long.class);
        //Long deletedKeysCount = redisTemplate.execute(script, Collections.emptyList(), StrKey + "*");
        //
        //log.info("成功删除前缀为 {} 的所有键,共删除 {} 个键", StrKey, deletedKeysCount);

    }

    /**
     * List类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceList(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForList().rightPush(ListKey, "value" + i);
        }
        log.info("使用List类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }

    /**
     * List类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedList(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 构造批量数据
        List<String> values = IntStream.range(0, dataCount)
                .mapToObj(i -> "value" + i)
                .collect(Collectors.toList());

        // 批量插入
        stringRedisTemplate.opsForList().rightPushAll(ListKey, values);

        log.info("使用List类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }

    /**
     * Hash类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceHash(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForHash().put(HashKey, "key" + i, "value" + i);
        }
        log.info("使用Hash类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }

    /**
     * Hash类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedHash(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 构造批量数据
        Map<String, String> hashData = IntStream.range(0, dataCount)
                .boxed()
                .collect(Collectors.toMap(i -> "key" + i, i -> "value" + i));

        // 批量插入
        stringRedisTemplate.opsForHash().putAll(HashKey, hashData);

        log.info("使用Hash类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }

    /**
     * Set类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceSet(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForSet().add("lps::test_set", "value" + i);
        }
        log.info("使用Set类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }

    /**
     * Set类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedSet(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 批量插入
        stringRedisTemplate.opsForSet().add("lps::test_set", Arrays.toString(IntStream.range(0, dataCount)
                .mapToObj(i -> "value" + i).distinct().toArray()));

        log.info("使用Set类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }

    /**
     * Geo类型测试循环插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testInsertPerformanceGeo(int dataCount) {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < dataCount; i++) {
            stringRedisTemplate.opsForGeo().add("lps::test_geo", generateValidPoint(i), "location" + i);
        }
        log.info("使用Geo类型循环插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - beginTime);
    }

    /**
     * Geo类型测试批量处理插入性能
     *
     * @param dataCount 插入的数据总量
     */
    public void testBatchInsertOptimizedGeo(int dataCount) {
        long startTime = System.currentTimeMillis();

        // 构造批量数据
        List<RedisGeoCommands.GeoLocation<String>> geoLocations = IntStream.range(0, dataCount)
                .mapToObj(i -> new RedisGeoCommands.GeoLocation<>("location" + i,
                        generateValidPoint(i)))
                .collect(Collectors.toList());

        // 批量插入
        stringRedisTemplate.opsForGeo().add("lps::test_geo", geoLocations);

        log.info("使用Geo类型批量插入{}条数据,总耗时为: {}ms", dataCount, System.currentTimeMillis() - startTime);
    }

    /**
     * 生成合法的 Geo 数据点
     */
    private Point generateValidPoint(int index) {
        // 生成经度 [-180, 180]
        double longitude = (index % 360) - 180;

        // 生成纬度 [-85.05112878, 85.05112878]
        double latitude = ((index % 170) - 85) * 0.1;

        return new Point(longitude, latitude);
    }
}

5. 总结与优化建议

  • 批量插入性能远远高于循环插入,尤其是在数据量较大时,差距更为明显。
  • 使用 Redis Pipeline 或批量操作接口是提高 Redis 性能的有效方法。
  • 在批量操作时,尽量将数据准备在内存中再一次性提交到 Redis,减少网络开销。
  • Geo 类型插入需注意经纬度合法范围,避免报错。

通过这些优化方法,Redis 的插入性能可以得到显著提升,在高并发场景下尤为重要。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

oneplus6线刷、trwp、magisk(apatch)、LSPosed、Shamiko、Hide My Applist

oneplus6线刷android10.0.1 oneplus6线刷包(官方android10.0.1)下载、线刷教程&#xff1a; OnePlus6-brick-enchilada_22_K_52_210716_repack-HOS-10_0_11-zip 启用开发者模式 设置 / 连续点击6次版本号 : 启用开发者模式设置/开发者模式/{打开 usb调试, 打开 网络adb调试,…

node.js中使用express.static()托管静态资源

express.static()定义 express.static(root, [options])是一个中间件函数&#xff0c;负责为Express应用提供静态资源服务。它允许你指定一个或多个目录作为静态资源的根目录&#xff0c;当客户端请求这些资源时&#xff0c;Express会查找并返回对应的文件。 安装express npm i…

【含开题报告+文档+PPT+源码】基于SSM的社区老人服务系统设计与实现

开题报告 在当前人口老龄化趋势明显以及信息化社会发展背景下&#xff0c;基于 SSM 框架构建的社区老人服务系统具有深远的背景意义。首先&#xff0c;它响应了我国老龄化进程加快所带来的多元化、个性化养老服务需求&#xff0c;利用互联网技术为老年人提供便捷高效的在线申请…

Spring AI 框架使用的核心概念

一、模型&#xff08;Model&#xff09; AI 模型是旨在处理和生成信息的算法&#xff0c;通常模仿人类的认知功能。通过从大型数据集中学习模式和见解&#xff0c;这些模型可以做出预测、文本、图像或其他输出&#xff0c;从而增强各个行业的各种应用。 AI 模型有很多种&…

学习与理解LabVIEW中多列列表框项名和项首字符串属性

多列列表框控件在如下的位置&#xff1a; 可以对该控件右击&#xff0c;如下位置&#xff0c;即可设置该控件的显示项&#xff1a; 垂直线和水平线指的是上图中组成单元格的竖线和横线&#xff08;不包括行首列首&#xff09; 现在介绍该多列列表框的两个属性&#xff0c;分别…

(Keil)MDK-ARM各种优化选项详细说明、实际应用及拓展内容

参考 MDK-ARM各种优化选项详细说明、实际应用及拓展内容 本文围绕MDK-ARM优化选项,以及相关拓展知识(微库、实际应用、调试)进行讲述,希望对你今后开发项目有所帮助。 1 总述 我们所指的优化,主要两方面: 1.代码大小(Size) 2.代码性能(运行时间) 在MDK-ARM中,优…

实时数据开发 | 怎么通俗理解Flink容错机制,提到的checkpoint、barrier、Savepoint、sink都是什么

今天学Flink的关键技术–容错机制&#xff0c;用一些通俗的比喻来讲这个复杂的过程。参考自《离线和实时大数据开发实战》 需要先回顾昨天发的Flink关键概念 检查点&#xff08;checkpoint&#xff09; Flink容错机制的核心是分布式数据流和状态的快照&#xff0c;从而当分布…

[译]Elasticsearch Sequence ID实现思路及用途

原文地址:https://www.elastic.co/blog/elasticsearch-sequence-ids-6-0 如果 几年前&#xff0c;在Elastic&#xff0c;我们问自己一个"如果"问题&#xff0c;我们知道这将带来有趣的见解&#xff1a; "如果我们在Elasticsearch中对索引操作进行全面排序会怎样…

七、SElinux

一、SElinux简介 SELinux是Security-Enhanced Linux的缩写&#xff0c;意思是安全强化的linuxSELinux 主要由美国国家安全局(NSA)开发&#xff0c;当初开发的目的是为了避免资源的误用传统的访问控制在我们开启权限后&#xff0c;系统进程可以直接访问当我们对权限设置不严谨时…

鸿蒙开发-音视频

Media Kit 特点 一般场合的音视频处理&#xff0c;可以直接使用系统集成的Video组件&#xff0c;不过外观和功能自定义程度低Media kit&#xff1a;轻量媒体引擎&#xff0c;系统资源占用低支持音视频播放/录制&#xff0c;pipeline灵活拼装&#xff0c;插件化扩展source/demu…

小程序25- iconfont 字体图标的使用

项目中使用到图标&#xff0c;一般由公司设计进行设计&#xff0c;设计好后上传到阿里巴巴矢量图标库 日常开发过程中&#xff0c;也可以通过 iconfont 图标库下载使用自带的图标 补充&#xff1a;使用 iconfont 图标库报错&#xff1a;Failed to load font 操作步骤&#xff…

vulhub之fastjson

fastjson 1.2.24 反序列化 RCE 漏洞(CVE-2017-18349) 漏洞简介 什么是json json全称是JavaScript object notation。即JavaScript对象标记法,使用键值对进行信息的存储。举个简单的例子如下: {"name":"BossFrank", "age":23, "isDevel…

Java语言程序设计 选填题知识点总结

第一章 javac.exe是JDK提供的编译器public static void main (String args[])是Java应用程序主类中正确的main方法Java源文件是由若干个书写形式互相独立的类组成的Java语言的名字是印度尼西亚一个盛产咖啡的岛名Java源文件中可以有一个或多个类Java源文件的扩展名是.java如果…

DevExpress控件 基本使用

DevExpress控件 一、DevExpress简介 1、所有编辑器的公共功能 全部都可以绑定数据&#xff1b; 全部都可以独立使用或用于由 Developer Express 提供的容器控件 (XtraGrid、XtraVerticalGrid、XtraTreeList 和 XtraBars) 内的内置编辑&#xff1b; 全部都使用相同的样式、外…

003 STM32基础、架构以及资料介绍——常识

注&#xff1a; 本笔记参考学习B站官方视频教程&#xff0c;免费公开交流&#xff0c;切莫商用。内容可能有误&#xff0c;具体以官方为准&#xff0c;也欢迎大家指出问题所在。 01什么是STM32&#xff08;宏观&#xff09; STM32属于一个微控制器&#xff0c;自带了各种常用通…

单片机_简单AI模型训练与部署__从0到0.9

IDE&#xff1a; CLion MCU&#xff1a; STM32F407VET6 一、导向 以求知为导向&#xff0c;从问题到寻求问题解决的方法&#xff0c;以兴趣驱动学习。 虽从0&#xff0c;但不到1&#xff0c;剩下的那一小步将由你迈出。本篇主要目的是体验完整的一次简单AI模型部署流程&#x…

2024最新YT-DLP使用demo网页端渲染

2024最新YT-DLP使用demo网页端渲染 前提摘要1.使用python的fastapi库和jinjia2库进行前端渲染2.代码实现1&#xff09;目录结构2&#xff09;代码style.cssindex.htmlresult.htmlmain.pyrun.py 3&#xff09;运行测试命令端运行 3.项目下载地址 前提摘要 2024最新python使用yt…

C0034.在Ubuntu中安装的Qt路径

Qt安装路径查询 在终端输入qmake -v如上中/usr/lib/x86_64-linux-gnu就是Qt的安装目录&#xff1b;

【STL】10.set与map的模拟实现

一、源码及框架分析 SGI-STL30版本源代码&#xff0c;map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等及个头文件中。 map和set的实现结构框架核心部分截取出来如下&#xff1a; // set #ifndef __SGI_STL_INTERNAL_TREE_H #include <stl_tree.h> #endif …

AI模型---安装cuda与cuDNN

1.安装cuda 先打开cmd 输入nvidia-smi 查看显卡支持cuda对应的版本&#xff1a; 然后去英伟达官网下载cuda&#xff08;外网多刷几次&#xff09; https://developer.nvidia.com/cuda-toolkit-archive 注意对应版本 安装过程中如果显示如下图&#xff1a; 请安装visual Stu…