SpringBoot项目里怎么简单高效使用Redis?我选择使用Lock4j

在这里插入图片描述

文章目录

  • 前言
  • 正文
    • 1、Lock4j的代码仓库
    • 2、pine-manage-common-redis的项目结构
    • 3、pine-manage-common-redis 的完整代码
      • 3.1 maven依赖:pom.xml
      • 3.2 redis连接参数:application.yaml
      • 3.3 RedisCache.java
      • 3.4 CacheConfig.java
      • 3.5 RedissonClientUtil.java
      • 3.6 SpringBeanUtil.java
      • 3.7 RedisLock.java
      • 3.8 RedisLockJsonKeyFunction.java
    • 4、pine-manage-common-redis的使用

前言

在平时使用SpringBoot框架时,有些业务场景会需要使用到Redis。但是,常见的Redis使用方式有好几种:

  • spring-boot-starter-data-redis:这是Spring Boot官方提供的Redis starter,它基于Spring Data Redis,提供了对Redis的集成支持。它默认使用Lettuce作为Redis客户端,但也支持Jedis客户端。通过这个starter,可以快速地在Spring Boot中整合、使用Redis,进行数据缓存、会话管理等操作。

  • spring-boot-starter-integration:这个starter提供了Spring Integration的支持,可以与Redis结合使用,实现分布式锁等功能。

  • spring-integration-redis:这是Spring Integration项目的一部分,提供了与Redis的集成支持,可以用于实现分布式锁等高级功能。

  • redisson-spring-boot-starter:Redisson是一个在Java环境下的Redis客户端,它提供了一系列的分布式数据结构和服务,如分布式锁、原子变量、集合等。这个starter简化了Redisson在Spring Boot中的配置和使用。

  • spring-boot-starter-data-redis-reactive:基于Webflux的响应式redis组件。

一般而言,我们会选择其中的一个。但是最近笔者发现了小黑鸟https://baomidou.com/resources/eco-system/ 的一个开源组件,就试着用了下。最后得到的结果是:真香!!!
在这里插入图片描述

这个Lock4j 本身是主要用于做分布式锁的。但是我们加入缓存组件,就能很容易得到一个具备缓存功能,同时支持分布式锁的一个小工具。

正文

1、Lock4j的代码仓库

https://gitee.com/baomidou/lock4j

Lock4j 本身支持集成多种Redis的连接器,我这次主要使用Redisson的集成。

我的集成项目实例仓库地址:https://gitee.com/fengsoshuai/pine-manage-system.git

进入pine-manage-system项目后,pine-manage-common-redis 模块是本文的重点。

注意:我的项目使用了java17版本,SpringBoot版本是3.3.4,如果想直接复用,需要自己调整。

2、pine-manage-common-redis的项目结构

在这里插入图片描述

  • com.pine.common.redis.cache :缓存包,实现了redis做缓存时的基本方法。
  • com.pine.common.redis.config:配置包,配置了缓存参数,redisson的相关配置,还有Spring获取Bean的工具类。
  • com.pine.common.redis.lock:redis做分布式锁的包装,实现了常用的工具方法。并自定义了redis key的拼接方法。

3、pine-manage-common-redis 的完整代码

3.1 maven依赖:pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.pine</groupId>
        <artifactId>pine-manage-common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>pine-manage-common-redis</artifactId>
    <packaging>jar</packaging>

    <name>pine-manage-common-redis</name>
    <url>http://maven.apache.org</url>

    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <lock4j.version>2.2.7</lock4j.version>
        <redisson.boot.version>3.25.2</redisson.boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- 使用lock4j实现分布式锁   https://gitee.com/baomidou/lock4j/-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>lock4j-core</artifactId>
            <version>${lock4j.version}</version>
        </dependency>
        <!-- 引入redisson-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>${redisson.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
            <version>${lock4j.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>


        <!-- Spring Boot Starter Cache for integration -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
    </dependencies>
</project>

3.2 redis连接参数:application.yaml

# redis配置 -使用时需要配置自己的redis
spring:
  data:
    redis:
      host: localhost
      port: 6379

3.3 RedisCache.java

package com.pine.common.redis.cache;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.util.Objects;

/**
 * redis缓存
 *
 * @author pine manage
 * @since 2024-08-13
 */
@Slf4j
public class RedisCache {

    @Resource(name = "redissonCacheManager")
    private CacheManager redissonCacheManager;

    /**
     * 获取缓存
     *
     * @param cacheName 缓存名称
     * @param key       缓存key
     * @return 缓存数据
     */
    public Object get(String cacheName, String key) {
        log.info("RedisCache获取缓存,cacheName={}, key={}", cacheName, key);
        Cache cache = redissonCacheManager.getCache(cacheName);
        if (Objects.isNull(cache)) {
            return null;
        }

        // 从缓存中获取数据
        return cache.get(key);
    }

    /**
     * 设置缓存
     *
     * @param cacheName 缓存名称
     * @param key       缓存key
     * @param value     缓存数据
     */
    public void set(String cacheName, String key, Object value) {
        log.info("RedisCache设置缓存,cacheName={}, key={}, value={}", cacheName, key, value);
        Cache cache = redissonCacheManager.getCache(cacheName);
        if (Objects.isNull(cache)) {
            return;
        }

        // 将数据放入缓存
        cache.put(key, value);
    }

    /**
     * 移除缓存
     *
     * @param cacheName 缓存名称
     * @param key       缓存key
     */
    public void remove(String cacheName, String key) {
        log.info("RedisCache移除缓存,cacheName={}, key={}", cacheName, key);
        Cache cache = redissonCacheManager.getCache(cacheName);
        if (Objects.isNull(cache)) {
            return;
        }

        // 从缓存中移除数据
        cache.evict(key);
    }

    /**
     * 移除所有缓存
     *
     * @param cacheName 缓存名称
     */
    public void removeAll(String cacheName) {
        log.info("RedisCache移除所有缓存,cacheName={}", cacheName);
        Cache cache = redissonCacheManager.getCache(cacheName);
        if (Objects.isNull(cache)) {
            return;
        }

        // 从缓存中移除数据
        cache.clear();
    }
}

3.4 CacheConfig.java

package com.pine.common.redis.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.pine.common.redis.cache.RedisCache;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.spring.cache.RedissonSpringCacheManager;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 缓存配置
 *
 * @author pine manage
 * @since 2024-08-13
 */
@Configuration
public class CacheConfig {

    @Bean(name = "redissonCacheManager")
    @ConditionalOnMissingBean
    public CacheManager redissonCacheManager(@Autowired RedissonClient redissonClient) {
        // 可以自定义缓存配置
        return new RedissonSpringCacheManager(redissonClient);
    }

    @Bean
    @ConditionalOnMissingBean
    public RedisCache redisCache() {
        return new RedisCache();
    }

    @Bean
    public RedissonAutoConfigurationCustomizer redissonAutoConfigurationCustomizer() {
        // 增加支持序列化java8的时间
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        JsonJacksonCodec jsonJacksonCodec = new JsonJacksonCodec(objectMapper);
        return config -> config.setCodec(jsonJacksonCodec);
    }
}

3.5 RedissonClientUtil.java

package com.pine.common.redis.config;

import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;

import java.time.Duration;

/**
 * redissonClient 工具类
 *
 * @author pine manage
 * @since 2024-08-22
 */
public class RedissonClientUtil {

    private static RedissonClient redissonClient;

    public static RedissonClient getRedissonClient() {
        init();
        return redissonClient;
    }

    /**
     * 设置缓存
     *
     * @param key               key
     * @param value             value
     * @param timeToLiveSeconds 失效时间(单位:秒)
     */
    public static void setCacheWithExpiration(String key, Object value, long timeToLiveSeconds) {
        init();
        RBucket<Object> bucket = redissonClient.getBucket(key);
        // 设置缓存值和过期时间
        bucket.set(value, Duration.ofSeconds(timeToLiveSeconds));
    }

    /**
     * 设置缓存
     *
     * @param key   key
     * @param value value
     */
    public static void setCache(String key, Object value) {
        init();
        RBucket<Object> bucket = redissonClient.getBucket(key);
        // 设置缓存值
        bucket.set(value);
    }

    /**
     * 获取缓存
     *
     * @param key key
     * @return value
     */
    public static Object getCache(String key) {
        init();
        RBucket<Object> bucket = redissonClient.getBucket(key);
        return bucket.get();
    }

    /**
     * 移除缓存
     *
     * @param key key
     */
    public static void removeCache(String key) {
        init();
        redissonClient.getBucket(key).delete();
    }


    private static void init() {
        if (redissonClient == null) {
            redissonClient = SpringBeanUtil.getByClass(RedissonClient.class);
        }
    }
}

3.6 SpringBeanUtil.java

package com.pine.common.redis.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

/**
 * springbean工具类
 *
 * @author pine manage
 * @since 2024-08-09
 */
@Component
public class SpringBeanUtil implements BeanFactoryAware {

    private static BeanFactory beanFactory;

    @Override
    public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
        SpringBeanUtil.beanFactory = beanFactory;
    }

    public static <T> T getByClass(Class<T> clazz) {
        return beanFactory.getBean(clazz);
    }
}

3.7 RedisLock.java

package com.pine.common.redis.lock;

import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.pine.common.redis.config.SpringBeanUtil;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Function;

/**
 * redis锁
 *
 * @author pine manage
 * @since 2024-08-09
 */
public class RedisLock {

    private static LockTemplate lockTemplate;

    /**
     * 获取锁超时时间
     */
    private static final Long LIMIT_STREAM_ACQUIRE_TIMEOUT = 0L;
    private static final Long ACQUIRE_TIMEOUT = 3000L;

    /**
     * 锁过期时间
     */
    private static final Long EXPIRE = 5000L;

    /**
     * redis分布式锁(redisson自动续锁)
     *
     * @param bizRunnable 业务逻辑
     * @param key         锁key
     */
    public static void lock(Runnable bizRunnable, String key, Long acquireTimeout) {
        initLockTemplate();
        // 获取锁超时时间,默认3秒
        acquireTimeout = Optional.ofNullable(acquireTimeout).orElse(ACQUIRE_TIMEOUT);
        // expire锁过期时间为-1:不过期,redisson 自动续锁
        LockInfo lockInfo = lockTemplate.lock(key, -1L, acquireTimeout);
        if (lockInfo == null) {
            throw new RuntimeException("获取锁失败");
        }

        try {
            bizRunnable.run();
            lockTemplate.releaseLock(lockInfo);
        } catch (Exception e) {
            lockTemplate.releaseLock(lockInfo);
            throw e;
        }
    }

    /**
     * redis分布式锁(redisson自动续锁)
     *
     * @param bizCallable 业务逻辑
     * @param key         锁key
     */
    public static <Result> Result lock(Callable<Result> bizCallable, String key, Long acquireTimeout) throws Exception {
        initLockTemplate();
        // 获取锁超时时间,默认3秒
        acquireTimeout = Optional.ofNullable(acquireTimeout).orElse(ACQUIRE_TIMEOUT);
        // expire锁过期时间为-1:不过期,redisson 自动续锁
        LockInfo lockInfo = lockTemplate.lock(key, -1L, acquireTimeout);
        if (lockInfo == null) {
            throw new RuntimeException("获取锁失败");
        }

        try {
            Result result = bizCallable.call();
            lockTemplate.releaseLock(lockInfo);
            return result;
        } catch (Exception e) {
            lockTemplate.releaseLock(lockInfo);
            throw e;
        }
    }

    /**
     * 加锁限流<br>
     * <b>此处注意:上锁后不手动解锁,等待过期时间自动解锁</b>
     *
     * @param param 锁参数
     */
    public static void lockAndLimitStream(Object param) {
        lockAndLimitStream(param, null, null, new RedisLockJsonKeyFunction());
    }

    /**
     * 加锁限流<br>
     * <b>此处注意:上锁后不手动解锁,等待过期时间自动解锁</b>
     *
     * @param expire         锁过期时间
     * @param acquireTimeout 获取锁超时时间
     */
    public static void lockAndLimitStream(Object param, Long expire, Long acquireTimeout) {
        lockAndLimitStream(param, expire, acquireTimeout, new RedisLockJsonKeyFunction());
    }

    /**
     * 加锁限流<br>
     * <b>此处注意:上锁后不手动解锁,等待过期时间自动解锁</b>
     *
     * @param expire         锁过期时间
     * @param acquireTimeout 获取锁超时时间
     * @param keyFunction    计算锁key的函数
     */
    public static void lockAndLimitStream(Object param, Long expire, Long acquireTimeout, Function<Object, String> keyFunction) {
        initLockTemplate();
        // 锁过期时间默认5秒
        expire = Optional.ofNullable(expire).orElse(EXPIRE);
        // 获取锁超时时间默认0秒
        acquireTimeout = Optional.ofNullable(acquireTimeout).orElse(LIMIT_STREAM_ACQUIRE_TIMEOUT);

        // 计算锁key
        String key = keyFunction.apply(param);
        // 尝试获取锁
        LockInfo lockInfo = lockTemplate.lock(key, expire, acquireTimeout);

        // 获取锁失败
        if (lockInfo == null) {
            throw new RuntimeException("调用过于频繁,业务处理中,请稍后再试");
        }
    }


    /**
     * 初始化lockTemplate
     */
    private static void initLockTemplate() {
        if (lockTemplate == null) {
            lockTemplate = SpringBeanUtil.getByClass(LockTemplate.class);
        }
        Objects.requireNonNull(lockTemplate, "lockTemplate is null");
    }
}

3.8 RedisLockJsonKeyFunction.java

package com.pine.common.redis.lock;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;

/**
 * redis锁key生成函数
 *
 * @author pine manage
 * @since 2024-08-09
 */
public class RedisLockJsonKeyFunction implements Function<Object, String> {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final Lock LOCK = new ReentrantLock();

    /**
     * Applies this function to the given argument.
     *
     * @param object the function argument
     * @return the function result
     */
    @Override
    public String apply(Object object) {
        return serializeToJson(object);
    }


    /**
     * 序列化对象为json
     *
     * @param object 对象
     * @return json
     */
    private static String serializeToJson(Object object) {
        try {
            LOCK.lock();
            return OBJECT_MAPPER.writeValueAsString(object);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }
}

4、pine-manage-common-redis的使用

在要使用的模块中,引入如下依赖:

        <dependency>
            <groupId>com.pine</groupId>
            <artifactId>pine-manage-common-redis</artifactId>
            <version>${pine-manage-common-redis.version}</version>
        </dependency>

随后直接使用RedisLock的静态方法即可,比如:

// 限流
RedisLock.lockAndLimitStream(triggerContext, expire, acquireTimeout);

而如果要使用缓存功能,则直接注入 RedisCache,然后使用即可,比如:

@Resource
protected RedisCache redisCache;

// 设置缓存
redisCache.set(CacheNameConstant.SYS_CONFIG_CACHE_NAME, sysConfig.getConfigKey(), newSysConfigBo);

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

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

相关文章

Python | Leetcode Python题解之第509题斐波那契数

题目&#xff1a; 题解&#xff1a; class Solution:def fib(self, n: int) -> int:if n < 2:return nq [[1, 1], [1, 0]]res self.matrix_pow(q, n - 1)return res[0][0]def matrix_pow(self, a: List[List[int]], n: int) -> List[List[int]]:ret [[1, 0], [0, …

Redisson(三)应用场景及demo

一、基本的存储与查询 分布式环境下&#xff0c;为了方便多个进程之间的数据共享&#xff0c;可以使用RedissonClient的分布式集合类型&#xff0c;如List、Set、SortedSet等。 1、demo <parent><groupId>org.springframework.boot</groupId><artifact…

spygalss cdc 检测的bug(二)

当allow_qualifier_merge设置为strict的时候&#xff0c;sg是要检查门的极性的。 如果qualifier和src经过与门汇聚&#xff0c;在同另一个src1信号或门汇聚&#xff0c;sg是报unsync的。 假设当qualifier为0时&#xff0c;0&&src||src1src1&#xff0c;src1无法被gat…

Mysql入门3——多表操作、事务、索引

Mysql入门3——多表操作、事务、索引 一、多表设计 ​ 在项目开发中&#xff0c;在进行数据库表的结构设计时&#xff0c;会根据业务需求及业务模块之前的关系&#xff0c;分析并设计表的结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表之间也存在着各种关系&am…

基于SSM的智慧篮球馆预约系统

前言 近些年&#xff0c;随着中国经济发展&#xff0c;人民的生活质量逐渐提高&#xff0c;对网络的依赖性越来越高&#xff0c;通过网络处理的事务越来越多。随着智慧篮球馆预约的常态化&#xff0c;如果依然采用传统的管理方式&#xff0c;将会为工作人员带来庞大的工作量&a…

css设置滚动条样式

效果图&#xff1a; // 滚动条样式 div::-webkit-scrollbar {width: 4px; } /* 滚动条滑块&#xff08;里面小方块&#xff09; */ div::-webkit-scrollbar-thumb {border-radius: 10px;-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);opacity: 0.2;background-color…

【面试经典150】day 8

#1024程序员节 | 征文# 作为一个未来的程序员&#xff0c;现在我要继续刷题了。 力扣时刻。 目录 1.接雨水 2.罗马数字转整数 3.最后一个单词的长度 4.最长公共前缀 5.反转字符串中的单词 1.接雨水 好好好好好好&#xff0c;一开始就接雨水。我记得接了n次了。。。 痛苦战…

【读书笔记·VLSI电路设计方法解密】问题25:为什么时钟如此重要

时钟是一种在高电平和低电平之间振荡的电信号。它通常是一个具有预定周期(频率)的方波,如图3.6所示。在同步数字电路中,时钟信号协调芯片上所有电路元件的动作。电路在时钟信号的上升沿、下降沿或两者的边缘处变为活动状态以实现同步。时钟信号相关问题是任何VLSI芯片设计中…

ASP.NET Core 8.0 中使用 Hangfire 调度 API

在这篇博文中&#xff0c;我们将引导您完成将 Hangfire 集成到 ASP.NET Core NET Core 项目中以安排 API 每天运行的步骤。Hangfire 是一个功能强大的库&#xff0c;可简化 .NET 应用程序中的后台作业处理&#xff0c;使其成为调度任务的绝佳选择。继续阅读以了解如何设置 Hang…

HarmonyOS NEXT初级案例:网络数据请求

使用HTTP访问网络 “HTTP协议”的全称:超文本传输协议(Hyper Text Transfer Protocol)。 一、添加网络管理权限 在“module.json5”文件中添加网络访问权限配置: "module": {"requestPermissions": [{"name":"ohos.permission.INTER…

【leetcode】动态规划

19. 918 环形子数组的最大和 题目&#xff1a; 给定一个长度为 n 的环形整数数组 nums &#xff0c;返回 nums 的非空 子数组 的最大可能和 。 环形数组 意味着数组的末端将会与开头相连呈环状。形式上&#xff0c; nums[i] 的下一个元素是 nums[(i 1) % n] &#xff0c; nums…

《2024中国泛娱乐出海洞察报告》解析,垂直且多元化方向发展!

随着以“社交”为代表的全球泛娱乐市场规模不断扩大以及用户需求不断细化&#xff0c;中国泛娱乐出海产品正朝着更加垂直化、多元化的方向发展。基于此&#xff0c;《2024中国泛娱乐出海洞察报告》深入剖析了中国泛娱乐行业出海进程以及各细分赛道出海现状及核心特征。针对中国…

Python游戏开发超详细第二课/一个小游戏等制作过程(入门级篇共2节)

直播内容&#xff0c;这里都用大多用照片代替了哈&#xff0c;因为在写一遍很累&#xff0c;哥哥姐姐理解一下抱歉抱歉 一个是我懒的写一遍&#xff0c;但是刚学的兄弟姐妹可不许学我偷懒哈 二防止有人偷懒&#xff0c;直接复制粘贴代码&#xff0c;所以为了方便帮助你们学习&a…

【AIGC】ChatGPT应用之道:如何打破`专家`幻象,提升AI协作质量

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;ChatGPT的实际能力用户对ChatGPT的常见误解超越误解&#xff0c;合理设定期望总结 &#x1f4af;超越“专家”幻想设定合理的期望总结 &#x1f4af;提升人工智能协作质量…

寻找大自然的颜色

走在停停&#xff0c;停停走走&#xff0c;恍惚间一天过去了&#xff0c;转瞬间一年过去了&#xff0c;身边的一切在变化又不在变化&#xff0c;生活是自己的又不是自己的。 今天是个特殊的日子&#xff0c;其实前几天对我而言就算特殊的日子了&#xff0c;一个心里暗暗等待着却…

python之数据结构与算法(数据结构篇)-- 集合

一、集合的概念 所谓的编程中的”集合“&#xff0c;其实和高中数学中集合是一样的的。比如&#xff1a;羊村和狼堡看作一个集合&#xff0c;而狼堡中的"灰太狼"、"红太狼"、"小灰灰"则可看作狼堡中的元素&#xff0c;同理&#xff0c;羊村中的…

通过火山云API来实现:流式大模型语音对话

这里我们需要在火山云语音控制台开通大模型的流式语音对话、获取豆包模型的apiKey&#xff0c;开通语音合成项目。 这里使用的豆包模型是Doubao-lite&#xff0c;延迟会更低一些配置说明 这里一共有四个文件&#xff0c;分别是主要的fastAPI、LLM、STT、文件 TTS中需要配置 ap…

洛谷 U411986 数的范围(二分模板)

题意&#xff1a;在一个有序序列里面找某个值的初始出现下标和最后出现下标&#xff0c;如果该值不存在&#xff0c;输出-1 -1。 整数二分模板题&#xff0c;该题主要用来练习如何写两种情况下的二分函数的代码模板。 1&#xff09;upper_bound函数&#xff1a;用来寻找边界点A…

鸿蒙是必经之路

少了大嘴的发布会&#xff0c;老实讲有点让人昏昏入睡。关于技术本身的东西&#xff0c;放在后面。 我想想来加把油~ 鸿蒙发布后褒贬不一&#xff0c;其中很多人不太看好鸿蒙&#xff0c;一方面是开源性、一方面是南向北向的利益问题。 不说技术的领先点&#xff0c;我只扯扯…

香橙派5(RK3588)使用npu加速yolov5推理的部署过程

香橙派5使用npu加速yolov5推理的部署过程 硬件环境 部署过程 模型训练(x86主机) 在带nvidia显卡(最好)的主机上进行yolo的配置与训练, 获取最终的best.pt模型文件, 详见另一篇文档 模型转换(x86主机) 下载airockchip提供的yolov5(从pt到onnx) 一定要下这个版本的yolov5, …