3.rabbitMQ之发布确认高级和整合springboot(重要)找了很多博客整理出来的

news2024/11/18 19:35:36

1.极端情况下 rabbitMQ需要重启,导致消息投递失败(生产者发消息全部丢失)(交换机或者队列出问题)
生产者需要把数据放到缓存,用定时任务重新发送
解决方法:
0.必须配置文件写

   spring.rabbitmq.publisher-confirm-type=correlated
   spring.rabbitmq.publisher-returns=true
  1. correlationDate数据 ack是否确定消息发送成功,cause是失败的原因
  @Component
                class    xxx  实现  RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback//由于是只是他rabbit的内部类,需要手动设置
                  @Autowired 
                       private RabbitTemplate  rabbitTemplate;
                  @PostConstruct  //@Autowired>@PostConstruct在构造器之后执行这个方法
                  public void init(){ 
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnCallback(this);
                 }

-----2.生产者 加个发送的id和信息,加上发送信息的最后一个参数

 CorrelationData correlationData1=new CorrelationData("1");//代表传入的id

------3.故意改错交换机名和队列名导致失败
------队列挂了(消息也丢失,需要交换机退回消息)-------

-------4.类 继续实现 ReturnCallback接口(只有路由不成功才调用)(还是要注入rabbit)
--------完整代码--------
//配置类 通知被退回的消息和id,可以自己存到数据库保存,等MQ正常后在生产

  @Slf4j
@Component
public class MyCallBack implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback{
    @Autowired
    RabbitTemplate rabbitTemplate;
    @PostConstruct
    void init(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id=correlationData!=null?correlationData.getId():"";
        if (ack){
            log.info("收到消息id为{}",id);
        }else {
            log.info("没有收到消息,id为{},原因为{}",id,cause);
        }
    }

    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
            log.info("路由失败,消息为{},退回原因{},交换机名{},routingKey:{}",new String(message.getBody()),replyText,exchange,routingKey);
    }


}

//生产者


public class ProducerController {
 public static final String CONFIRM_EXCHANGE_NAME = "business.exchange";
 @Autowired
 private RabbitTemplate rabbitTemplate;



 @GetMapping("sendMessage/{message}")
 public void sendMessage(@PathVariable String message){

 //指定消息 id 为 1
CorrelationData correlationData1=new CorrelationData("1");
 String routingKey="rk.001";

rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME,routingKey,message+routingKey,correlationData1);
 CorrelationData correlationData2=new CorrelationData("2");
 routingKey="key2";
 //这样只知道交换机有问题,而不知道路由有问题
 rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME,routingKey,message+routingKey,correlationData2);//设置好corelation的id数据
  log.info("发送消息内容:{}",message);
  
  }
}

// !!!也可以用下面的解决方案,如果不喜欢用整合其他框架

2.备份交换机(也是队列不成功,上面的解决方案) 可以不用重新发送,走备份交换机到消费者消费和报警消费者失败
工作流程如下图mq6
请添加图片描述

     1.队列转发到另外的交换机
     2.交换机比路由先出错会先报交换机的错误,路由的错误不报
注意!!!需要在业务交换机声明 备份交换机
        //核心步骤 声明业务 Exchange
 @Bean("confirmExchange")
 public DirectExchange confirmExchange(){
    ExchangeBuilder exchangeBuilder=ExchangeBuilder.directExchange(CONFIRM_EXCHANGE_NAME).durable(true).withArgument("alternate-exchange", BACKUP_EXCHANGE_NAME); //翻译为可变交换机,出错了改发送的交换机

 return (DirectExchange) exchangeBuilder.build();
 }
   ------完整代码------
    -------声明交换机和队列-----

```java
            @Configuration
public class ConfirmConfig {
 public static final String CONFIRM_EXCHANGE_NAME = "confirm.exchange";
 public static final String CONFIRM_QUEUE_NAME = "confirm.queue";

 public static final String BACKUP_EXCHANGE_NAME = "backup.exchange";
 public static final String BACKUP_QUEUE_NAME = "confirm.queue";
 public static final String WARNING_QUEUE_NAME = "warning.queue";

 //声明业务 Exchange
 @Bean("confirmExchange")
 public DirectExchange confirmExchange(){
    ExchangeBuilder exchangeBuilder=ExchangeBuilder.directExchange(CONFIRM_EXCHANGE_NAME).durable(true).withArgument("alternate-exchange", BACKUP_EXCHANGE_NAME);

 return (DirectExchange) exchangeBuilder.build();
 }
 // 声明确认队列
 @Bean("confirmQueue")
 public Queue confirmQueue(){
 return QueueBuilder.durable(CONFIRM_QUEUE_NAME).build();
 }
 // 声明确认队列绑定关系
 @Bean
 public Binding queueBinding(@Qualifier("confirmQueue") Queue queue,
                             @Qualifier("confirmExchange") DirectExchange exchange){
 return BindingBuilder.bind(queue).to(exchange).with("key1");
 }
 //声明备份 Exchange
 @Bean("backupExchange")
 public FanoutExchange backupExchange(){
  return new FanoutExchange(BACKUP_EXCHANGE_NAME);
 }
 // 声明备份队列
 @Bean("backupQueue")
 public Queue backupQueue(){
  return QueueBuilder.durable(BACKUP_QUEUE_NAME).build();
 }
 // 声明警告队列
 @Bean("warningQueue")
 public Queue warningQueue(){ return QueueBuilder.durable(WARNING_QUEUE_NAME).build();}
 // 声明backup队列绑定关系
 @Bean
 public Binding backupQueueBindingBackup(@Qualifier("backupQueue") Queue queue,
                             @Qualifier("backupExchange") FanoutExchange exchange){
  return BindingBuilder.bind(queue).to(exchange);
 }
 // 声明warning队列绑定关系
 @Bean
 public Binding warningQueueBindingBackup(@Qualifier("warningQueue") Queue queue,
                                         @Qualifier("backupExchange") FanoutExchange exchange){
  return BindingBuilder.bind(queue).to(exchange);
 }
}

-------交换机和队列路由的错误回调-----

@Slf4j
@Component
public class MyCallBack implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback{
    @Autowired
    RabbitTemplate rabbitTemplate;
    @PostConstruct
    void init(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id=correlationData!=null?correlationData.getId():"";
        if (ack){
            log.info("收到消息id为{}",id);
        }else {
            log.info("没有收到消息,id为{},原因为{}",id,cause);
        }
    }

    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
            log.info("路由失败,消息为{},退回原因{},交换机名{},routingKey:{}",new String(message.getBody()),replyText,exchange,routingKey);
    }


}

-------生产者-----

@RestController
@RequestMapping("/confirm")
@Slf4j
public class ProducerController {
 public static final String CONFIRM_EXCHANGE_NAME = "confirm.exchange";
 @Autowired
 private RabbitTemplate rabbitTemplate;
 @Autowired
 private MyCallBack myCallBack;

 @GetMapping("sendMessage/{message}")
 public void sendMessage(@PathVariable String message){
 //指定消息 id 为 1
 CorrelationData correlationData1=new CorrelationData("1");
 String routingKey="key1";
 
rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME,routingKey,message+routingKey,correlationData1);
 CorrelationData correlationData2=new CorrelationData("2");
 routingKey="key2"; //这里是错误的routingKey,会报错
 //这样只知道交换机有问题,而不知道路由有问题
 rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME,routingKey,message+routingKey,correlationData2);
  log.info("发送消息内容:{}",message);
 }
}

-------消息消费者(消息正常消费)-------

@Component
@Slf4j
public class ConfirmConsumer {
  public static final String CONFIRM_QUEUE_NAME = "confirm.queue";
  @RabbitListener(queues =CONFIRM_QUEUE_NAME)
  public void receiveMsg(Message message){
   String msg=new String(message.getBody());
   log.info("接受到队列 confirm.queue 消息:{}",msg);
  }
}

-------警告消费者(消费失败转发到备份交换机,和队列进行消费)-------

@Component
@Slf4j
public class WarningConsumer {
 public static final String WARNING_QUEUE_NAME = "warning.queue";
 @RabbitListener(queues = WARNING_QUEUE_NAME)
  public void receiveWarningMsg(Message message) {
  String msg = new String(message.getBody());
  log.error("报警发现不可路由消息:{}", msg);
  }
}

3.其他知识点

1.幂等性问题,消息被重复消费,需要先判断全局唯一id是否消费后,再消费
         1.使用mysql,唯一id,有性能瓶颈,不推荐
         2.使用redis原子性 执行setnx命令天然有幂等性

4.优先队列(在队列加优先级) 0-255 越大越优先(如天猫的大客户是小米,消息优先被消费发短信通知)

0.最好用最大优先级为0-10,因为消费者让mq排序需要时间消耗cpu和内存
1.排队后,在生产者设置最大入队后出队参数,不然全部一个一个消费完,不能看到效果

   //生产者设置消息优先级 mq界面会出现Pri
   //设置优先队列的方法
          map(发消息channel): 
                HashMap<String, Object> arg = new HashMap<>();
    arg.put("x-max-priority",10);
    channel.queueDeclare(QUEUE_NAME,Duration,false,false,arg);
    //或者
    AMQP.BasicProperties properties = new
            AMQP.BasicProperties().builder().priority(10).build();

完整代码
------生产者----------

          public class AckPriorMsg {
    public static final String QUEUE_NAME="hello1";
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        Channel channel = MQRabbitUtil.getChannel();
        channel.confirmSelect();//代表要确认磁盘中mq已经存储了数据,先写



        boolean Duration=true;
        //队列名
        //队列消息是否持久化到磁盘,默认在内存中
        //队列是否只供一个消费者消费(不共享)
        //是否自动删除,开新队列
        //其他参数
        HashMap<String, Object> arg = new HashMap<>();
        arg.put("x-max-priority",10);
        channel.queueDeclare(QUEUE_NAME,Duration,false,false,arg);
        AMQP.BasicProperties properties = new
                AMQP.BasicProperties().builder().priority(10).build();
        for (int i = 1; i <11; i++) {


            String message = "info" + i;
            if (i == 5) { //默认优先级是5,这里相当于是发送了不同优先级的消息
                channel.basicPublish("", QUEUE_NAME, properties, message.getBytes());
            } else{
                channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            }
            //交换机
            //队列名
            //设置消息持久化
            //二进制

                boolean flag = channel.waitForConfirms();
                if (flag) {
                System.out.println("消息已经写入磁盘的确认");

            }
        }

    }
}

------消费者----------

public class ConsumerPrior1 {
    public static final String QUEUE_NAME="hello1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = MQRabbitUtil.getChannel();
        Map<String, Object> params = new HashMap();
        //设置了才是优先队列
        params.put("x-max-priority", 10);
        channel.basicQos(1);
        channel.queueDeclare(QUEUE_NAME, true, false, false, params);
        DeliverCallback deliverCallback=(consumerTag, delivery)->{
            SleepUtils.sleep(1);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
            System.out.println("消息处理快接收:"+new String(delivery.getBody(),"UTF-8"));
            System.out.println(consumerTag);
            //确认的标志
            //是否批量应答



        };
        CancelCallback cancelCallback=(var1)->{

            System.out.println("应答失败");
        };
        //消费, 项目队列名,是否自动应答!!!(就是要手动处理还是被动处理)
        //失败的回调,消费者取消消费的回调(都要lambda表达式)
        boolean IsAck=false;
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, cancelCallback);
        System.out.println("worker1正在等待接收消息");
    }

}

–重要------------springboot版本--------
—优先队列springboot配置文件要设置为手动确认和交换机是direct----
//写个方便设置优先级的工具类

@Component
@AllArgsConstructor
public class FileMessageSender {
 
    private static final String EXCHANGE = "priority-exchange";
 
    private static final String ROUTING_KEY_PREFIX = "priority.queue.test";
    @Autowired
    private final RabbitTemplate rabbitTemplate;
 
    /**
     * 发送设置有优先级的消息
     *
     * @param priority 优先级
     */
    public void sendPriorityMessage(String content, Integer priority) {
        rabbitTemplate.convertAndSend(EXCHANGE, ROUTING_KEY_PREFIX , content,
                message -> {
                    message.getMessageProperties().setPriority(priority);
                    return message;
                });
    }
 
}

-------------下面是不用工具类的代码,由于我看了许多博客才写成的下面的代码------------
----配置类定义配置—

@Configuration
public class ConfirmConfig {
 //----------优先队列-----------
 public static final String BUSINESS_ROUTING_KEY = "rk.001";
 public static final String BUSINESS_QUEUE = "business.queue";
 public static final String BUSINESS_EXCHANGE = "business.exchange";

 /**
  * 声明业务队列的交换机
  */
 @Bean
 public DirectExchange directExchange() {
  return new DirectExchange(BUSINESS_EXCHANGE);
 }


 /**
  * 声明业务队列
  */
 @Bean
 public Queue priorityQueue() {
  Map<String, Object> args = new HashMap<>();
  // 设置队列最大优先级
  args.put("x-max-priority", 10);
  args.put("x-queue-mode", "lazy"); //随便定义惰性队列(在磁盘取数据,而不是内存) 可以和优先队列一起使用
  return QueueBuilder.durable(BUSINESS_QUEUE).withArguments(args).build();
 }

 /**
  * 声明业务队列和业务交换机的绑定关系
  */
 @Bean
 public Binding businessBinding(Queue priorityQueue, DirectExchange directExchange) {
  return BindingBuilder.bind(priorityQueue).to(directExchange).with(BUSINESS_ROUTING_KEY);
 }

-------生产者设置队列优先级--------

@RestController
@RequestMapping("/confirm")
@Slf4j
public class ProducerController {
 public static final String CONFIRM_EXCHANGE_NAME = "business.exchange";
 @Autowired
 private RabbitTemplate rabbitTemplate;



 @GetMapping("sendMessage/{message}")
 public void sendMessage(@PathVariable String message){

 //指定消息 id 为 1
// CorrelationData correlationData1=new CorrelationData("1");
 String routingKey="rk.001";
//
//rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME,routingKey,message+routingKey,correlationData1);
// CorrelationData correlationData2=new CorrelationData("2");
// routingKey="key2";
// //这样只知道交换机有问题,而不知道路由有问题
// rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME,routingKey,message+routingKey,correlationData2);
//  log.info("发送消息内容:{}",message);

  for (int i = 0; i < 10000; i++) {
    if(i==5){
     rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME, routingKey, "消息来自 ttl 为 xS 的队列: "+message+i, correlationData ->{
      correlationData.getMessageProperties().setPriority(100);
      return correlationData;
     });
    }else if(i==1){
    rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME, routingKey, "消息来自 ttl 为 xS 的队列: "+message+i, correlationData ->{
     correlationData.getMessageProperties().setPriority(6);
     return correlationData;
    });
   }else {
     rabbitTemplate.convertAndSend(CONFIRM_EXCHANGE_NAME, routingKey, "消息来自 ttl 为 xS 的队列: "+message+i, correlationData ->{
         correlationData.getMessageProperties().setPriority(1);
         return correlationData;
     });
    }

  }


 }
}

-------消费者消费------

@Component
@Slf4j
public class ConfirmConsumer {
  public static final String CONFIRM_QUEUE_NAME = "business.queue";

  @RabbitListener(queues =CONFIRM_QUEUE_NAME)
  public void receiveMsg(String msg,Channel channel,Message message) throws IOException {
    HashMap<String, Object> arg = new HashMap<>();
    arg.put("x-max-priority",10); //配置类消费者都设置最大优先级
    arg.put("x-queue-mode", "lazy"); //配置类消费者都设置惰性队列,可以和优先队列一起使用
    channel.queueDeclare(CONFIRM_QUEUE_NAME,true,false,false,arg);
   log.info("接受到队列 confirm.queue 消息:{}",msg);
  }
}


  



}

5.惰性队列(消息保存在磁盘中,正常放在内存) 应用场景怕内存不够宕机,存在磁盘可以大量存储,缺点是性能不好(springboot完整代码如上)
内存只有索引,管理界面查看只是使用几kb内存,差不多完全存在磁盘了

           //生产者和消费者都加上参数
             HashMap<String, Object> arg = new HashMap<>();
        arg.put("x-max-priority",10);
        //惰性队列,存在磁盘中
         arg.put("x-queue-mode", "lazy");
        channel.queueDeclare(QUEUE_NAME,Duration,false,false,arg);

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

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

相关文章

appuploader 入门使用

回想一下我们发布 iOS 应用&#xff0c;不仅步骤繁琐&#xff0c;非常耗时。一旦其中一步失误了&#xff0c;又得重新来。作为一名优秀的工程师不应该让这些重复的工作在浪费我们的人生。在软件工程里面&#xff0c;我们一直都推崇把重复、流程化的工作交给程序完成。这次的文章…

【shell脚本】for循环语句

循环语句与函数 一、循环与遍历1.1循环1.2遍历1.3循环与遍历 二、for循环2.1for循环的基本格式2.2for循环小实验2.3双层for循环实验 三、while循环3.1 while格式 四、跳出循环4.1continue跳出循环实验4.2break跳出循环实验 一、循环与遍历 1.1循环 循环 (Loop) 是计算机编程中…

不会前端,怎么快速打造属于自己的个人博客?

个人博客 简介提前准备 一、初始化vuepress项目二、页面配置首页配置顶部配置顶部导航栏路由配置侧边导航栏配置 三、打包部署四、数据统计插槽自定义插槽配置整体结构页面效果 项目地址 简介 主要教大家如何快速搞一个属于自己的博客网站&#xff0c;特别是一些不怎么会前端的…

【C++】——类与对象(上)

文章目录 1. 前言2. 面向过程和面向对象3. 类的引入4. 类的定义4.1 类的俩种定义方式 5. 类的访问限定符及封装5.1 类的访问限定符5.2 封装 6. 类的作用域7. 类的实例化8. 类对象的存储方式9. this指针9.1 this指针特性 10. 结尾 1. 前言 今天我们来学习C初期最重要的知识点&a…

用于无线传感器网络路由的改进leach协议(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 当前&#xff0c;无线传感器由于技术的发展得到更加广泛的应用&#xff0c;针对无线传感器网络&#xff08;WSN&#xff09;的…

linux重装mmsegmentation

前言 换了个电脑&#xff0c;就想着把之前的mmsegmentation-V0.26.0代码放到新环境&#xff0c;结果踩了不少坑~ 过程 官方步骤 0 安装miniconda 1 创建conda 环境 最开始用的是python3.10&#xff0c;后来发现版本太高不是一件好事&#xff0c;所以装的python3.8 2 安装…

FineBI 6.0入门基础(二)

在图形中分析 组件还可以进行复制,如下图 复制后,切换为【自定义图表】 1.将【毛利额】调整为折线(在图形属性里面进行调整) 2.由于【毛利额】和【毛利额环比增长率】数值差距较大,可将指标中的【毛利额环比增长率】调整为右值轴 3.将图例调整显示位置(组件样式-图例…

ZooKeeper 避坑指南: ZooKeeper 3.6.4 版本 BUG 导致的数据不一致问题

作者&#xff1a;子葵 背景 ZooKeeper 作为分布式系统的元数据中心&#xff0c;对外服务的数据一致性需要得到很好的保证&#xff0c;但是一些老版本的 ZooKeeper 在一些情况下可能无法保证数据的一致性&#xff0c;导致依赖 ZooKeeper 的系统出现异常。 某用户使用 3.4.6 版…

回归问题(AI笔记)

人工智能 回归问题 1943 年&#xff0c;心理学家沃伦麦卡洛克 (Warren McCulloch)和数理逻辑学家沃尔特皮茨(Walter Pitts)通过对生物神经元的研究&#xff0c; 提出了模拟生物神经元机制的人工神经网络的数学模型 &#xff0c;这一成果被美国神经学家弗 兰克罗森布拉特(Frank …

(别再手动点APP了)UiAutomator2自动化测试框架带你玩转APP操作

目录 前言 一、uiautomator/uiautomator2的前生今世 1.官方文档介绍 2.梳理一下脉络 3.三款框架对比 二、uiautomator2简介 1.项目组成 2.工作原理 三、环境搭建 1.安装uiautomator2 2.初始化设备 3.init时都干了啥&#xff1f; 四、基础操作 1.连接设备 2.命令…

手把手教你搭建 Webpack 5 + React 项目

前言 在平时工作中&#xff0c;为减少开发成本&#xff0c;一般都会使用脚手架来进行开发&#xff0c;比如 create-react-app。脚手架都会帮我们配置好了 webpack&#xff0c;但如果想自己搭建 webpack 项目要怎么做呢&#xff1f;这边文章将介绍如何使用 webpack 5 来搭建 re…

HNU-操作系统OS-实验Lab2

OS_Lab2_Experimental report 湖南大学信息科学与工程学院 计科 210X wolf &#xff08;学号 202108010XXX&#xff09; 前言 实验一过后大家做出来了一个可以启动的系统&#xff0c;实验二主要涉及操作系统的物理内存管理。操作系统为了使用内存&#xff0c;还需高效地管理…

C++全栈知识体系 2.0

C 全栈知识体系 一个记录C知识的学习网站&#xff01; 包含内容: C(基础、函数、知识点、IO框架、新特性), 算法, 数据库(MySQL、ElasticSearch、Redis), 编程四大件, 架构, 微服务, 中间件(ZeroMQ、Dubbo、Consul、Logstash、Kong), 工具, 部署(Docker、k8s、Istio), 项目(开源…

YOLOv7环境配置的一些细节

评论区和私信问我问题的同学们不要急&#xff0c;你们的问题我一直在研究&#xff0c;只是还没成功(>﹏<)&#xff0c;如果完成了我会第一时间发出来并通知你的(≧∇≦)/ 本文将讲解YOLOv7环境配置的一些细节&#xff08;YOLOv5环境配置也适用&#xff0c;之前在配gpu版本…

【移动端网页布局】流式布局案例 ⑦ ( 水平排列的图片链接 2 | 浮动设置 | 盒子模型类型设置 | 结构伪类选择器 )

文章目录 一、水平排列的图片链接样式及核心要点1、实现效果2、HTML 结构3、CSS 样式 二、完整代码示例1、HTML 标签结构2、CSS 样式3、展示效果 一、水平排列的图片链接样式及核心要点 1、实现效果 实现如下样式 , 水平排列的图片链接 , 第一个图片占宽度的 50% , 第二第三个 …

【视频解读】Window上安装和使用autogluon V0.7

1.使用conda安装的python环境 教程使用的是极简版miniconda,由于我们的电脑中安装了anaconda&#xff0c;所以不需要进行进一步安装。python版本为3.9&#xff0c;博客里面有anaconda和python版本的对应关系。注意查看版本autogluon V0.4需要3.8或者3.9和3.10&#xff0c;pip版…

分类预测 | MATLAB实现基于PSO-NN、SVM、KNN、DT的多特征数据分类预测,二分类及多分类

分类预测 | MATLAB实现基于PSO-NN、SVM、KNN、DT的多特征数据分类预测&#xff0c;二分类及多分类 目录 分类预测 | MATLAB实现基于PSO-NN、SVM、KNN、DT的多特征数据分类预测&#xff0c;二分类及多分类分类效果基本描述程序设计参考资料 分类效果 基本描述 Matlab实现基于PSO…

智能家居项目

文章目录 一、功能描述二、整体框架结构及编译2.1、整体框架2.2、编译Makefile 三、工厂模式四、守护进程udev五、监控视频储存六、遇到的问题和未解决的问题七、代码流程图7.1、树莓派&#xff08;8线程 &#xff0c;2进程&#xff09;7.2、手机APP 八、内网穿透&#xff08;实…

机器学习(五):基于KNN模型对高炉发电量进行回归预测分析

文章目录 专栏导读1、KNN简介2、KNN回归模型介绍3、KNN模型应用-高炉发电量预测3.1数据集信息:3.2属性信息3.3数据准备3.4数据标准化和划分数据集3.5寻找最佳K值3.6建立KNN模型预测4、完整代码专栏导读 ✍ 作者简介:i阿极,CSDN Python领域新星创作者,专注于分享python领域知…

二叉树的最近公共祖先

1题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它…