RabbitMQ--进阶篇

news2025/5/18 14:50:47

RabbitMQ


客户端整合Spring Boot

添加相关的依赖

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

编写配置文件,配置RabbitMQ的服务信息

spring:
  rabbitmq:
    host: 192.168.200.100
    port: 5672
    username: guest
    password: 123456
    virtual-host: /
logging:
  level:
    com.atguigu.mq.listener.MyMessageListener: info

监听消息与发送消息(这里如果想要演示的明白的话需要创建两个Boot工程分别作为生产端与服务端来进行演示操作)

//=================================监听消息使用注解的方式来完成=============================
@Component
@Slf4j
public class MyMessageListener {
  
    public static final String EXCHANGE_DIRECT = "exchange.direct.order";  
    public static final String ROUTING_KEY = "order";  
    public static final String QUEUE_NAME  = "queue.order";  
  
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = QUEUE_NAME, durable = "true"),
            exchange = @Exchange(value = EXCHANGE_DIRECT),
            key = {ROUTING_KEY}
    ))
    public void processMessage(String dateString,
                               Message message,
                               Channel channel) {
        log.info(dateString);
    }
  
}
​
//=================================发送消息使用组件的方式来完成=============================
@SpringBootTest  
public class RabbitMQTest {  
  
    public static final String EXCHANGE_DIRECT = "exchange.direct.order";  
    public static final String ROUTING_KEY = "order";
  
    @Autowired  
    private RabbitTemplate rabbitTemplate;
  
    @Test  
    public void testSendMessage() {  
        rabbitTemplate.convertAndSend(  
                EXCHANGE_DIRECT,   
                ROUTING_KEY,   
                "Hello atguigu");  
    }  
  
}

注解

示例1:

@RabbitListener(bindings = @QueueBinding(
         value = @Queue(value = QUEUE_NAME, durable = "true"),
         exchange = @Exchange(value = EXCHANGE_DIRECT),
         key = {ROUTING_KEY}
))
  • @RabbitListener注解

    • 作用:自动绑定指定队列进行消息监听,支持直接队列名绑定表达式占位符配置等方式,自动反序列化消息体到方法参数,支持多种参数类型(POJO/Message/byte[]),管理消息确认模式(自动/手动ACK),配置并发消费者线程池,实现消息重试和死信处理

    • binding属性

      • 作用:指定交换机和队列之间的绑定关系,指定当前方法要监听的队列如果RabbitMQ服务器上没有这里指定的交换机和队列,那么框架底层的代码会创建它们

      • @QueueBinding注解:

        • 作用:声明需要绑定的队列与交换机的信息

        • value属性:使用@Queue注解来指定队列信息

        • exchange属性:使用@Exchange注解来指定交换机信息

        • key属性:使用{}来指定路由键信息

示例2:

@RabbitListener(queues = {QUEUE_ATGUIGU})

直接使用queues这个属性值,通过给这个属性进行赋值来直接指定需要监听的队列,优点是编写模式简洁精短,缺点是不能像示例1所写的那样在未创建交换机与队列以及设置其绑定关系时可以系统帮忙设置以防发生报错。需要在RabbitMQ的可视化界面自己手动进行创建与绑定的过程

消息可靠性投递

故障及其解决方案

  • 故障情况1:消息没有发送到消息队列上面

  • 解决方案:

  • 故障情况2:消息成功发送到了消息队列,但是消息队列服务宕机了。原本保存在内存里面的消息也丢失了

  • 解决方案:将消息持久化到硬盘上面,哪怕服务器重启也不会导致消息丢失

  • 故障情况3:消息成功存入了消息队列,但是消费端出现了问题(宕机,抛出异常等)

  • 解决方案:

业务代码实现

生产者故障
  • 导入依赖,编写配置文件
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

注意:publisher-confirm-type和publisher-returns是两个必须要增加的配置,如果没有则本节功能不生效

spring:
  rabbitmq:
    host: 192.168.200.100
    port: 5672
    username: guest
    password: 123456
    virtual-host: /
    publisher-confirm-type: CORRELATED # 交换机的确认
    publisher-returns: true # 队列的确认
logging:
  level:
    com.atguigu.mq.config.MQProducerAckConfig: info
  • 创建配置类

在创建完配置类之后,重写相应的可提升消息可靠性的方法后,我们还需要对RabbitTemplate的功能进行增强,因为回调函数所在对象必须设置到RabbitTemplate对象中才能生效。原本RabbitTemplate对象并没有生产者端消息确认的功能,要给它设置对应的组件才可以。

方法名方法功能所属接口接口所属类
confirm()确认消息是否发送到交换机ConfirmCallbackRabbitTemplate
returnedMessage()确认消息是否发送到队列ReturnsCallbackRabbitTemplate
设置组件调用的方法所需对象类型
setConfirmCallback()ConfirmCallback接口类型
setReturnCallback()ReturnCallback接口类型
//================================配置类的逻辑,确保消息到达交换机、到达队列=====================================
@Component
@Slf4j
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback{
​
    @Autowired
    private RabbitTemplate rabbitTemplate;
​
    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
        //初始化RabbitMQ模板,将重写的方法重新加入到rabbitTemplate中
    }
​
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            log.info("消息发送到交换机成功!数据:" + correlationData);
        } else {
            log.info("消息发送到交换机失败!数据:" + correlationData + " 原因:" + cause);
        }
    }
​
    @Override
    public void returnedMessage(ReturnedMessage returned) {
        log.info("消息主体: " + new String(returned.getMessage().getBody()));
        log.info("应答码: " + returned.getReplyCode());
        log.info("描述:" + returned.getReplyText());
        log.info("消息使用的交换器 exchange : " + returned.getExchange());
        log.info("消息使用的路由键 routing : " + returned.getRoutingKey());
    }
}

注解说明:

  • 发送消息

@SpringBootTest  
public class RabbitMQTest {  
  
    public static final String EXCHANGE_DIRECT = "exchange.direct.order";
    public static final String ROUTING_KEY = "order";
  
    @Autowired  
    private RabbitTemplate rabbitTemplate;
  
    @Test  
    public void testSendMessage() {  
        rabbitTemplate.convertAndSend(  
                EXCHANGE_DIRECT,   
                ROUTING_KEY,   
                "Hello atguigu");  
    }  
  
}

通过调整代码,测试如下三种情况:

  • 交换机正确、路由键正确

  • 交换机正确、路由键不正确,无法发送到队列

  • 交换机不正确,无法发送到交换机

RabbitMQ服务故障

我们直接重启docker容器就会发现,我们明明没有向队列中发送消息但是队列的消息速率图仍然显示有消息到达。这是因为刚才我们做实验时放入队列中的消息在docker重启完毕之后就从硬盘里面被移动到了MQ中。实际上RabbitMQ默认是配置了持久化的。表现在交换机是默认持久化的、队列是默认持久化的、消息是默认持久化的。在一些配置交换机与队列的注解里面就会看见底层是默认了持久化的。

消费者故障
  • 配置文件

spring:
  rabbitmq:
    host: 192.168.200.100
    port: 5672
    username: guest
    password: 123456
    virtual-host: /
    listener:
      simple:
        acknowledge-mode: manual # 把消息确认模式改为手动确认
  • 接收消息

@Component
@Slf4j
public class MyMessageListener {
​
    public static final String EXCHANGE_DIRECT = "exchange.direct.order";
    public static final String ROUTING_KEY = "order";
    public static final String QUEUE_NAME  = "queue.order";
​
    // 修饰监听方法
    @RabbitListener(
            // 设置绑定关系
            bindings = @QueueBinding(
​
                // 配置队列信息:durable 设置为 true 表示队列持久化;autoDelete 设置为 false 表示关闭自动删除
                value = @Queue(value = QUEUE_NAME, durable = "true", autoDelete = "false"),
​
                // 配置交换机信息:durable 设置为 true 表示队列持久化;autoDelete 设置为 false 表示关闭自动删除
                exchange = @Exchange(value = EXCHANGE_DIRECT, durable = "true", autoDelete = "false"),
​
                // 配置路由键信息
                key = {ROUTING_KEY}
    ))
    public void processMessage(String dataString, Message message, Channel channel) throws IOException {
​
        // 1、获取当前消息的 deliveryTag 值备用
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
​
        try {
            // 2、正常业务操作
            log.info("消费端接收到消息内容:" + dataString);
            
            // System.out.println(10 / 0);
​
            // 3、给 RabbitMQ 服务器返回 ACK 确认信息
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
​
            // 4、获取信息,看当前消息是否曾经被投递过
            Boolean redelivered = message.getMessageProperties().getRedelivered();
​
            if (!redelivered) {
                // 5、如果没有被投递过,那就重新放回队列,重新投递,再试一次
                channel.basicNack(deliveryTag, false, true);
            } else {
                // 6、如果已经被投递过,且这一次仍然进入了 catch 块,那么返回拒绝且不再放回队列
                channel.basicReject(deliveryTag, false);
            }
​
        }
    }
​
}

ACK与NACK机制:ACK(成功)消费者成功处理消息后,显式或隐式地向RabbitMQ服务器发送确认信号,告知消息已被正确处理,服务器可以安全移除该消息。在没有手动的在配置文件中声明时就是默认返回ACK数据;NACK(失败)消费者明确告知服务器消息处理失败,服务器可根据策略重新投递或丢弃消息(如进入死信队列)。

  • ACK是消息处理成功的“绿灯”,确保可靠性。

  • NACK是处理失败的“黄灯”,提供容错和重试机制。

  • 两者结合使用时,需通过重试策略、死信队列和幂等性设计,构建高可靠的分布式消息系统。

API说明:

①basicAck()方法:

  • 作用:给Broker返回ACK确认信息,表示消息已经在消费端成功消费,这样Broker就可以把消息删除了

  • 参数列表:

参数名称含义
long deliveryTagBroker给每一条进入队列的消息都设定一个唯一标识
boolean multiple取值为true:为小于、等于deliveryTag的消息批量返回ACK信息 取值为false:仅为指定的deliveryTag返回ACK信息

②basicNack()方法:

  • 作用:给Broker返回NACK信息,表示消息在消费端消费失败,此时Broker的后续操作取决于参数requeue的值

  • 参数列表:

参数名称含义
long deliveryTagBroker给每一条进入队列的消息都设定一个唯一标识
boolean multiple取值为true:为小于、等于deliveryTag的消息批量返回ACK信息 取值为false:仅为指定的deliveryTag返回ACK信息
boolean requeue取值为true:Broker将消息重新放回队列,接下来会重新投递给消费端 取值为false:Broker将消息标记为已消费,不会放回队列

③basicReject()方法:

  • 作用:根据指定的deliveryTag,对该消息表示拒绝

  • 参数列表:

参数名称含义
long deliveryTagBroker给每一条进入队列的消息都设定一个唯一标识
boolean requeue取值为true:Broker将消息重新放回队列,接下来会重新投递给消费端 取值为false:Broker将消息标记为已消费,不会放回队列

消费端限流

作用
  • 防止资源耗尽:避免消费者因处理速度跟不上消息到达速度,导致内存或线程资源耗尽。

  • 保护下游服务:防止突发流量压垮数据库等依赖服务。

  • 平衡负载:确保消费者处理能力与消息生产速率匹配。

实现

①yml文件配置,设置消费端的限流阈值为多少(prefetch参数)

spring:
  rabbitmq:
    host: 192.168.200.100
    port: 5672
    username: guest
    password: 123456
    virtual-host: /
    listener:
      simple:
        acknowledge-mode: manual
        prefetch: 1 # 设置每次最多从消息队列服务器取回多少消息
  • Prefetch Count(QoS设置)

    • 通过设置 prefetch count 参数,限制消费者未确认(unacknowledged)的最大消息数量。

    • 例如,若 prefetch=5,消费者最多同时处理5条消息,处理并确认后才会获取新消息。

    • 手动确认模式(Manual Acknowledgement)必须启用手动ACK(关闭自动确认),否则prefetch机制失效。

②消费与生产端的测试代码

//=====================生产端===============================
@Test  
public void testSendMessage() {
    for (int i = 0; i < 100; i++) {
        rabbitTemplate.convertAndSend(
                EXCHANGE_DIRECT,
                ROUTING_KEY,
                "Hello atguigu" + i);
    }
}
 
//=========================消费端===========================
// 2、正常业务操作
log.info("消费端接收到消息内容:" + dataString);
​
// System.out.println(10 / 0);
TimeUnit.SECONDS.sleep(1);
​
// 3、给 RabbitMQ 服务器返回 ACK 确认信息
channel.basicAck(deliveryTag, false);

③结果分析

在未配置消费端限流时,RabbitMQ的监视界面显示消息涌入100条瞬间就被在监视的消费端一扫而空,总消息数为0,但是在ACK的确认机制下Raabbit服务还在慢慢处理消息的确认信息并反馈给监视界面

在配置了消息限流之后,RabbitMQ的监视界面显示任然是消息涌入100条但是消息并非是一口气被消费端全部消费完成而是随着时间的推移慢慢的被消费取出,总消息数随着时间的变化而在变化,同样在ACK的机制下Rabbit服务还在慢慢处理消息的确认信息并反馈给监视界面

消息超时

RabbitMQ 的消息超时机制主要通过 TTL(Time-To-Live) 实现,允许为消息或队列设置存活时间,过期后消息会被自动删除或转移到死信队列。

TTL的两种设置方式

  • 队列级TTL
    • 定义为整个队列设置统一的过期时间,所有进入该队列的消息共享此 TTL(超时时间)。

    • 特点

      • 全局生效,优先级低于消息级 TTL。

      • 队列中消息的过期时间从入队时开始计算。

            // 设置队列参数:消息1分钟后过期
            Map<String, Object> args = new HashMap<>();
            args.put("x-message-ttl", 60000); // 单位:毫秒
            
            // 声明队列
            channel.queueDeclare("my_queue", true, false, false, args);
  • 消息级 TTL
    • 定义为单条消息设置独立的过期时间,优先级高于队列级 TTL。

    • 特点

      • 每条消息的 TTL 独立计算。

      • 过期时间从消息入队时开始计算(若消息被重新投递到其他队列,时间重新计算)。

    // 1、创建消息后置处理器对象  
    MessagePostProcessor messagePostProcessor = (Message message) -> {  
  
        // 设定 TTL 时间,以毫秒为单位
        message.getMessageProperties().setExpiration("5000");  
  
        return message;
    };
  
    // 2、发送消息  
    rabbitTemplate.convertAndSend(    
            EXCHANGE_DIRECT,     
            ROUTING_KEY,     
            "Hello atguigu", messagePostProcessor);   

消息超时的行为

  • 自动删除:当消息过期后,默认会直接从队列中删除。

  • 死信队列(Dead Letter Exchange): 若队列配置了死信交换机(DLX),过期消息会转移到 DLX 关联的队列,而非直接删除。

总结

  1. 支持队列级和消息级 TTL,后者优先级更高。

  2. 过期消息可自动删除或路由到死信队列。

  3. 实际应用中需注意过期检查机制的性能影响及潜在阻塞问题。 合理使用 TTL 可有效解决业务超时逻辑、资源释放等常见问题。

死信和死信队列

死信(Dead Letter)定义:在消息队列中无法被正常消费的消息称为死信(Dead Letter);通常产生的原因如下:

  1. 消息被拒绝(Rejected)且未设置重新入队(requeue=false

  2. 消息过期(TTL 超时)

  3. 队列达到最大长度(超过 x-max-length 限制时,头部或尾部消息被丢弃)

死信队列(Dead Letter Queue, DLQ)定义:专门用于接收死信的队列,需通过死信交换机(DLX) 路由。

核心作用

  • 收集异常消息,防止消息丢失

  • 提供消息审计和重试机制

  • 解耦主业务逻辑与错误处理逻辑

注意:一定要注意正常队列有诸多限定和设置,这样才能让无法处理的消息进入死信交换机

延迟队列

延迟队列(Delayed Queue)是一种特殊类型的消息队列,允许消息在指定的延迟时间后才被消费者获取和处理。RabbitMQ 本身不直接支持延迟队列

1. 基于 TTL + 死信队列的延迟队列(传统方案)

实现原理
  1. 消息设置 TTL:为消息或队列设置存活时间(TTL)。

  2. 绑定死信交换机:当消息过期后,通过死信交换机(DLX)路由到目标队列。

  3. 消费者监听目标队列:实现延迟消费效果。

2. 使用插件 rabbitmq-delayed-message-exchange(推荐方案)

RabbitMQ 官方提供的插件支持精确延迟消息投递消息在交换机层暂存,到期后路由到目标队列。

下载与启用插件:

wget https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/v3.13.0/rabbitmq_delayed_message_exchange-3.13.0.ez
mv rabbitmq_delayed_message_exchange-3.13.0.ez /var/lib/docker/volumes/rabbitmq-plugin/_data
# 登录进入容器内部
docker exec -it rabbitmq /bin/bash
​
# rabbitmq-plugins命令所在目录已经配置到$PATH环境变量中了,可以直接调用
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
​
# 退出Docker容器
exit
​
# 重启Docker容器
docker restart rabbitmq
//=====================生产端代码============================
@Test
public void testSendDelayMessage() {
    rabbitTemplate.convertAndSend(
            EXCHANGE_DELAY,
            ROUTING_KEY_DELAY,
            "测试基于插件的延迟消息 [" + new SimpleDateFormat("hh:mm:ss").format(new Date()) + "]",
            messageProcessor -> {
​
                // 设置延迟时间:以毫秒为单位(只有安装好插件之后才可以使参数生效)
                messageProcessor.getMessageProperties().setHeader("x-delay", "10000");
​
                return messageProcessor;
            });
}
 
//====================消费端代码============================
@Component  
@Slf4j
public class MyDelayMessageListener {
    
    public static final String QUEUE_DELAY = "queue.delay.video";
    
    @RabbitListener(queues = {QUEUE_DELAY})
    public void process(String dataString, Message message, Channel channel) throws IOException {  
        log.info("[生产者]" + dataString);
        log.info("[消费者]" + new SimpleDateFormat("hh:mm:ss").format(new Date()));
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
​
}
插件特性
  • 精确延迟:消息按设定的延迟时间精确投递。

  • 灵活配置:每条消息可独立设置延迟时间。

  • 资源高效:消息存储在交换机层,不占用队列资源。

效果展示:

3. 两种方案对比

特性TTL + 死信队列插件方案
延迟精度低(依赖队列处理速度)高(精确到毫秒)
灵活性需固定或逐条设置 TTL每条消息独立设置延迟
资源占用可能占用队列存储交换机层存储,更高效
部署复杂度无需额外插件需安装插件
适用场景短延迟(<1分钟)、简单场景长延迟、高精度、复杂需求

事务消息

RabbitMQ 的事务消息机制用于确保一组消息操作的原子性——要么全部成功提交到 Broker,要么全部回滚

配置类

//========================事务队列的相关配置====================
@Configuration
@Data
public class RabbitConfig {
​
    @Bean//添加事务消息的组件
    public RabbitTransactionManager transactionManager(CachingConnectionFactory connectionFactory) {
        return new RabbitTransactionManager(connectionFactory);
    }
​
    @Bean//增强RabbitTemplate开启事务消息模式
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setChannelTransacted(true);
        return rabbitTemplate;
    }
}
//====================消息生产端无事务版本==============================
@SpringBootTest
@Slf4j
public class RabbitMQTest {
​
    public static final String EXCHANGE_NAME = "exchange.tx.dragon";
    public static final String ROUTING_KEY = "routing.key.tx.dragon";
​
    @Resource
    private RabbitTemplate rabbitTemplate;
​
    @Test
    public void testSendMessageInTx() {
        // 1、发送第一条消息
        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING_KEY, "I am a dragon(tx msg ~~~01)");
​
        // 2、抛出异常
        log.info("do bad:" + 10 / 0);
​
        // 3、发送第二条消息
        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING_KEY, "I am a dragon(tx msg ~~~02)");
    }
​
}
​
//=======================消息生产端有事务版本===============================
@Test
@Transactional
@Rollback(value = false)
public void testSendMessageInTx() {
    // 1、发送第一条消息
    rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING_KEY, "I am a dragon(tx msg [commit] ~~~01)");
​
    // 2、发送第二条消息
    rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING_KEY, "I am a dragon(tx msg [commit] ~~~02)");
}

注意:请注意区分事务消息与消息可靠性投递这两者之间的关系。首先事务消息是不确保消息的可靠性投递的。他只限制相应的Java代码,在逻辑过程中不抛出异常就将消息发送到Broker上反之就会将消息回滚。

惰性队列

惰性队列(Lazy Queue)是 RabbitMQ 中一种特殊的队列类型,核心目标是通过优先将消息存储到磁盘而非内存,来优化系统资源使用,尤其适用于高吞吐、大消息量且允许一定延迟的场景。

特性普通队列惰性队列
消息存储优先级内存优先(除非消息标记为持久化)磁盘优先(无论消息是否持久化)
内存占用高(消息积压时易引发 OOM)低(消息直接写入磁盘)
消费延迟低(内存中直接读取)较高(需从磁盘加载到内存)
适用场景实时性要求高、消息量小消息量大、允许延迟、需避免内存耗尽

工作机制:

①消息到达队列时,直接持久化到磁盘(即使未显式标记为持久化消息),仅在需要传递给消费者时加载到内存。

默认仅缓存少量消息(如消费者预取值 prefetch 范围内的消息)。

消费者消费后,消息从磁盘删除。

优先级队列

优先级队列(Priority Queue)是 RabbitMQ 中一种特殊队列类型,允许消息按照优先级高低被消费,高优先级的消息会被优先处理。适用于需要差异化处理消息的场景(如 VIP 用户请求优先处理)。

特性说明
优先级范围支持 0-255 的优先级等级(实际受 Erlang 虚拟机限制,通常建议 0-10)
消费顺序高优先级消息先被消费,同优先级按 FIFO 顺序处理
实现原理队列内部维护多级子队列,按优先级排序消息
资源消耗略高于普通队列(需维护优先级索引)

在创建队列的时候添加参数x-max-priority,用来设置消息参数的最大优先等级。在后面创建的消息在设置等级参数的时候不能超过这个参数值。

//=======================生产端产生消息并为它设置优先等级================================
@SpringBootTest
public class RabbitMQTest {
​
    public static final String EXCHANGE_PRIORITY = "exchange.test.priority";
    public static final String ROUTING_KEY_PRIORITY = "routing.key.test.priority";
​
    @Resource
    private RabbitTemplate rabbitTemplate;
​
    @Test
    public void testSendMessage() {
        rabbitTemplate.convertAndSend(EXCHANGE_PRIORITY, ROUTING_KEY_PRIORITY, "I am a message with priority 1.", message->{
            message.getMessageProperties().setPriority(1);
            return message;
        });
    }
​
}
​
//==========================消费端接收消息===============================
@Slf4j
@Component
public class MyMessageProcessor {
​
    public static final String QUEUE_PRIORITY = "queue.test.priority";
​
    @RabbitListener(queues = {QUEUE_PRIORITY})
    public void processPriorityMessage(String data, Message message, Channel channel) throws IOException {
        log.info(data);
​
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
​
}

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

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

相关文章

Android Studio报错Cannot parse result path string:

前言 最近在写个小Demo&#xff0c;参考郭霖的《第一行代码》&#xff0c;学习DrawerLayout和NavigationView&#xff0c;不知咋地&#xff0c;突然报错Cannot parse result path string:xxxxxxxxxxxxx 反正百度&#xff0c;问ai都找不到答案&#xff0c;报错信息是完全看不懂…

关于网站提交搜索引擎

发布于Eucalyptus-blog 一、前言 将网站提交给搜索引擎是为了让搜索引擎更早地了解、索引和显示您的网站内容。以下是一些提交网站给搜索引擎的理由&#xff1a; 提高可见性&#xff1a;通过将您的网站提交给搜索引擎&#xff0c;可以提高您的网站在搜索结果中出现的机会。当用…

基于QT(C++)OOP 实现(界面)酒店预订与管理系统

酒店预订与管理系统 1 系统功能设计 酒店预订是旅游出行的重要环节&#xff0c;而酒店预订与管理系统中的管理与信息透明是酒店预订业务的关键问题所在&#xff0c;能够方便地查询酒店信息进行付款退款以及用户之间的交流对于酒店预订行业提高服务质量具有重要的意义。 针对…

机械元件杂散光难以把控?OAS 软件案例深度解析

机械元件的杂散光分析 简介 在光学系统设计与工程实践中&#xff0c;机械元件的杂散光问题对系统性能有着不容忽视的影响。杂散光会降低光学系统的信噪比、图像对比度&#xff0c;甚至导致系统功能失效。因此&#xff0c;准确分析机械元件杂散光并采取有效抑制措施&#xff0c…

游戏引擎学习第289天:将视觉表现与实体类型解耦

回顾并为今天的工作设定基调 我们正在继续昨天对代码所做的改动。我们已经完成了“脑代码&#xff08;brain code&#xff09;”的概念&#xff0c;它本质上是一种为实体构建的自组织控制器结构。现在我们要做的是把旧的控制逻辑迁移到这个新的结构中&#xff0c;并进一步测试…

【Linux网络】ARP协议

ARP协议 虽然我们在这里介绍 ARP 协议&#xff0c;但是需要强调&#xff0c;ARP 不是一个单纯的数据链路层的协议&#xff0c;而是一个介于数据链路层和网络层之间的协议。 ARP数据报的格式 字段长度&#xff08;字节&#xff09;说明硬件类型2网络类型&#xff08;如以太网为…

MUSE Pi Pro 开发板 Imagination GPU 利用 OpenCL 测试

视频讲解&#xff1a; MUSE Pi Pro 开发板 Imagination GPU 利用 OpenCL 测试 继续玩MUSE Pi Pro&#xff0c;今天看下比较关注的gpu这块&#xff0c;从opencl看起&#xff0c;安装clinfo指令 sudo apt install clinfo 可以看到这颗GPU是Imagination的 一般嵌入式中gpu都和hos…

多线程与线程互斥

我们初步学习完线程之后&#xff0c;就要来试着写一写多线程了。在写之前&#xff0c;我们需要继续来学习一个线程接口——叫做线程分离。 默认情况下&#xff0c;新创建的线程是joinable的&#xff0c;线程退出后&#xff0c;需要对其进行pthread_join操作&#xff0c;否则无法…

游戏引擎学习第287天:加入brain逻辑

Blackboard&#xff1a;动态控制类似蛇的多节实体 我们目前正在处理一个关于实体系统如何以组合方式进行管理的问题。具体来说&#xff0c;是在游戏中实现多个实体可以共同或独立行动的机制。例如&#xff0c;我们的主角拥有两个实体组成部分&#xff0c;一个是身体&#xff0…

continue通过我们的开源 IDE 扩展和模型、规则、提示、文档和其他构建块中心,创建、共享和使用自定义 AI 代码助手

​一、软件介绍 文末提供程序和源码下载 Continue 使开发人员能够通过我们的开源 VS Code 和 JetBrains 扩展以及模型、规则、提示、文档和其他构建块的中心创建、共享和使用自定义 AI 代码助手。 二、功能 Chat 聊天 Chat makes it easy to ask for help from an LLM without…

2025年EB SCI2区TOP,多策略改进黑翅鸢算法MBKA+空调系统RC参数辨识与负载聚合分析,深度解析+性能实测

目录 1.摘要2.黑翅鸢优化算法BKA原理3.改进策略4.结果展示5.参考文献6.代码获取7.读者交流 1.摘要 随着空调负载在电力系统中所占比例的不断上升&#xff0c;其作为需求响应资源的潜力日益凸显。然而&#xff0c;由于建筑环境和用户行为的变化&#xff0c;空调负载具有异质性和…

.NET 中管理 Web API 文档的两种方式

前言 在 .NET 开发中管理 Web API 文档是确保 API 易用性、可维护性和一致性的关键。今天大姚给大家分享两种在 .NET 中管理 Web API 文档的方式&#xff0c;希望可以帮助到有需要的同学。 Swashbuckle Swashbuckle.AspNetCore 是一个流行的 .NET 库&#xff0c;它使得在 AS…

【HTML】个人博客页面

目录 页面视图​编辑 页面代码 解释&#xff1a; HTML (<body>): 使用了更加语义化的HTML5标签&#xff0c;例如<header>, <main>, <article>, <footer>。文章列表使用了<article>包裹&#xff0c;结构清晰。添加了分页导航。使用了Font…

论文解读:ICLR2025 | D-FINE

[2410.13842] D-FINE: Redefine Regression Task in DETRs as Fine-grained Distribution Refinement D-FINE 是一款功能强大的实时物体检测器&#xff0c;它将 DETRs 中的边界框回归任务重新定义为细粒度分布细化&#xff08;FDR&#xff09;&#xff0c;并引入了全局最优定位…

9.DMA

目录 DMA —为 CPU 减负 DMA 的简介和使用场景 DMA 的例子讲解 STM32 的 DMA 框图和主要特性 ​编辑 DMA 的通道的对应通道外设 – DMA 和哪些外设使用 ​编辑​编辑ADC_DR 寄存器地址的计算 常见的数据滤波方法 ADCDMA 的编程 DMA —为 CPU 减负 DMA 的简介和使用场…

大语言模型 10 - 从0开始训练GPT 0.25B参数量 补充知识之模型架构 MoE、ReLU、FFN、MixFFN

写在前面 GPT&#xff08;Generative Pre-trained Transformer&#xff09;是目前最广泛应用的大语言模型架构之一&#xff0c;其强大的自然语言理解与生成能力背后&#xff0c;是一个庞大而精细的训练流程。本文将从宏观到微观&#xff0c;系统讲解GPT的训练过程&#xff0c;…

python基础语法(三-中)

基础语法3&#xff1a; 2.列表与元组&#xff1a; <1>.列表、元组是什么&#xff1f; 都用来存储数据&#xff0c;但是两者有区别&#xff0c;列表可变&#xff0c;元组不可变。 <2>.创建列表&#xff1a; 创建列表有两种方式&#xff1a; [1].a 【】&#x…

ZTE 7551N 中兴小鲜60 远航60 努比亚小牛 解锁BL 刷机包 刷root 展讯 T760 bl

ZTE 7551N 中兴小鲜60 远航60 努比亚小牛 解锁BL 刷机包 刷root 3款机型是一个型号&#xff0c;包通用&#xff0c; ro.product.system.modelZTE 7551N ro.product.system.nameCN_P720S15 #################################### # from generate-common-build-props # Th…

信息系统项目管理师高级-软考高项案例分析备考指南(2023年案例分析)

个人笔记整理---仅供参考 计算题 案例分析里的计算题就是进度、挣值分析、预测技术。主要考査的知识点有:找关键路径、求总工期、自由时差、总时差、进度压缩资源平滑、挣值计算、预测计算。计算题是一定要拿下的&#xff0c;做计算题要保持头脑清晰&#xff0c;认真读题把PV、…

产品经理入门(2)产品体验报告

产品体验报告大纲&#xff1a;重点在产品体验——优点。 1.产品概括 可以从各大平台搜产品介绍。 2.市场分析 按照产品方向分析各个指标——包括有效使用时间,市场规模等。 3. 用户分析——对用户通过各项指标画像。 4.产品体验——对各项功能与设计的体验。 5.报告总结