当前位置: 首页 > news >正文

RabbitMQ--基础篇

RabbitMQ


简介:RabbitMQ 是一种开源的消息队列中间件,你可以把它想象成一个高效的“邮局”。它专门负责在不同应用程序之间传递消息,让系统各部分能松耦合地协作

优势:

  • 异步处理:比如用户注册后,主程序将发送验证邮件的任务扔进队列就立刻返回,邮件服务后续慢慢处理,避免用户等待。

  • 削峰填谷:突然的流量高峰(如秒杀活动)会被队列缓冲,避免服务器被压垮。

  • 智能路由:通过交换机(Exchange)的四种路由策略(直连/主题/广播/头匹配),实现精准投递,比如将VIP用户的订单定向到专属客服队列。

  • 故障恢复:支持消息持久化和确认机制,即使服务器宕机,消息也不会丢失。

同步VS异步(以实际开发为例子进行说明):

  • 同步业务功能的耦合度高,异步耦合度低,可以达到解耦的效果

  • 同步业务流程响应的时间长,异步响应的时间短

  • 同步模式会导致并发压力向后进行传递,异步可以削峰限流

  • 同步模式下系统结构弹性不足,异步模式下系统弹性强,可扩展性强

注意:在实际开发中并不是说异步模式就完全优与同步模式,在一定的场景下使用异步模式是优化系统的架构,但是在一些其它的业务场景下需要同步来保证流程的完整性。所以说异步还是同步要跟据具体业务进行选择。

底层实现:

  • AMQP(Advanced Message Queuing Protocol):AMQP 是 跨语言的通用消息协议适合异构系统间的复杂通信。

  • JMS(Java Message Service):JMS是 Java 专属的 API 标准适合统一 Java 生态的消息处理。

主流的MQ产品对比

对比项RabbitMQActiveMQRocketMQKafka
开发语言ErlangJavaJavaScala/Java
维护方Rabbit(公司)Apache(社区)阿里(公司)Apache(社区)
核心机制基于 AMQP 协议的生产者-消费者模型基于 JMS 的消息传递模型分布式消息队列(Topic + Tag 分类)分布式流处理平台(发布-订阅模型)
协议支持AMQP、STOMP、MQTT、HTTP 插件AMQP、STOMP、OpenWire、REST、MQTT自定义协议(支持 TCP/HTTP)自定义协议(社区封装 HTTP 支持)
客户端语言官方:Erlang、Java、Ruby;社区:多语言Java、C/C++、.NET、Python、PHP官方:Java;社区:C++(不成熟)官方:Java;社区:Python、Go、Rust 等
可用性镜像队列、仲裁队列(Quorum Queue)主从复制主从复制分区(Partition) + 副本(Replica)
单机吞吐量约 10 万/秒约 5 万/秒10 万+/秒(阿里双十一验证)百万级/秒
消息延迟微秒级毫秒级毫秒级毫秒以内
消息确认完整 ACK/NACK 机制支持 JMS ACK 模式基于数据库持久化的消息表基于副本同步和 ISR 机制
功能特性✅ 低延迟、高并发、管理界面丰富✅ 老牌稳定、支持 JMS 规范✅ 高吞吐、阿里生态集成、事务消息✅ 高吞吐、流处理、大数据场景专用
适用场景复杂路由、实时业务(如支付订单)传统企业级系统(Java 生态)电商高并发场景(如秒杀、订单)日志采集、实时分析、流式计算

原生RabbitMQAPI调用:

//=========================================发送消息的代码示例=================================
public class Producer {  public static void main(String[] args) throws Exception {  // 创建连接工厂  ConnectionFactory connectionFactory = new ConnectionFactory();  // 设置主机地址  connectionFactory.setHost("192.168.200.100");  // 设置连接端口号:默认为 5672connectionFactory.setPort(5672);// 虚拟主机名称:默认为 /connectionFactory.setVirtualHost("/");// 设置连接用户名;默认为guest  connectionFactory.setUsername("guest");// 设置连接密码;默认为guest  connectionFactory.setPassword("123456");// 创建连接  Connection connection = connectionFactory.newConnection();  // 创建频道  Channel channel = connection.createChannel();  // 声明(创建)队列  // queue      参数1:队列名称  // durable    参数2:是否定义持久化队列,当 MQ 重启之后还在  // exclusive  参数3:是否独占本次连接。若独占,只能有一个消费者监听这个队列且 Connection 关闭时删除这个队列  // autoDelete 参数4:是否在不使用的时候自动删除队列,也就是在没有Consumer时自动删除  // arguments  参数5:队列其它参数  channel.queueDeclare("simple_queue", true, false, false, null);  // 要发送的信息  String message = "你好;小兔子!";  // 参数1:交换机名称,如果没有指定则使用默认Default Exchange  // 参数2:路由key,简单模式可以传递队列名称  // 参数3:配置信息  // 参数4:消息内容  channel.basicPublish("", "simple_queue", null, message.getBytes());  System.out.println("已发送消息:" + message);  // 关闭资源  channel.close();  connection.close();  }  }
//=========================================接收消息的代码示例=================================
public class Consumer {  public static void main(String[] args) throws Exception {  // 1.创建连接工厂  ConnectionFactory factory = new ConnectionFactory();  // 2. 设置参数  factory.setHost("192.168.200.100");  factory.setPort(5672);  factory.setVirtualHost("/");  factory.setUsername("guest");factory.setPassword("123456");  // 3. 创建连接 Connection        Connection connection = factory.newConnection();  // 4. 创建Channel  Channel channel = connection.createChannel();  // 5. 创建队列  // 如果没有一个名字叫simple_queue的队列,则会创建该队列,如果有则不会创建  // 参数1. queue:队列名称  // 参数2. durable:是否持久化。如果持久化,则当MQ重启之后还在  // 参数3. exclusive:是否独占。  // 参数4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉  // 参数5. arguments:其它参数。  channel.queueDeclare("simple_queue",true,false,false,null);  // 接收消息  DefaultConsumer consumer = new DefaultConsumer(channel){  // 回调方法,当收到消息后,会自动执行该方法  // 参数1. consumerTag:标识  // 参数2. envelope:获取一些信息,交换机,路由key...  // 参数3. properties:配置信息  // 参数4. body:数据  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("consumerTag:"+consumerTag);  System.out.println("Exchange:"+envelope.getExchange());  System.out.println("RoutingKey:"+envelope.getRoutingKey());  System.out.println("properties:"+properties);  System.out.println("body:"+new String(body));  }  };  // 参数1. queue:队列名称  // 参数2. autoAck:是否自动确认,类似咱们发短信,发送成功会收到一个确认消息  // 参数3. callback:回调对象  // 消费者类似一个监听程序,主要是用来监听消息  channel.basicConsume("simple_queue",true,consumer);  }  }

封装RabbitMQ工具类:

public class ConnectionUtil {  //跟据自己服务的具体需求进行相关ip+端口的配置(动态变化)public static final String HOST_ADDRESS = "192.168.200.100";  public static Connection getConnection() throws Exception {  // 定义连接工厂  ConnectionFactory factory = new ConnectionFactory();  // 设置服务地址  factory.setHost(HOST_ADDRESS);  // 端口  factory.setPort(5672);  //设置账号信息,用户名、密码、vhost  factory.setVirtualHost("/");  factory.setUsername("guest");  factory.setPassword("123456");  // 通过工程获取连接  Connection connection = factory.newConnection();  return connection;  }  public static void main(String[] args) throws Exception {  Connection con = ConnectionUtil.getConnection();  // amqp://guest@192.168.200.100:5672/  System.out.println(con);  con.close();  }  }

RabbitMQ体系结构:

  • 生产者(Producer):发送消息到 RabbitMQ 的应用程序。

  • 消费者(Consumer):从队列中接收并处理消息的应用程序。

  • 交换机(Exchange):接收生产者消息,根据类型和路由规则将消息分发到队列。

    • 四大类型

类型路由规则典型场景
Direct精确匹配 Routing Key(如 order.pay一对一精准投递(如支付成功通知)
Topic通配符匹配(如 order.**.pay多服务订阅同一类消息(如日志分类)
Fanout广播到所有绑定队列(无视 Routing Key群发通知(如系统公告)
Headers通过消息头(Headers)键值对匹配复杂条件路由(需灵活匹配时)
  • 队列(Queue):定义交换机与队列之间的映射关系,指定路由规则

  • 信道(Channel):复用 TCP 连接的轻量级虚拟链路,减少资源消耗。

  • 虚拟主机(Virtual Host):逻辑隔离的“消息域”,不同 vhost 间资源(交换机、队列)互不干扰。

总结:RabbitMQ 通过 生产者-交换机-队列-消费者 模型实现异步通信,核心在于灵活的路由规则(交换机类型)和可靠性保障(持久化、确认机制)。

基础篇

工作模式

  • 简单模式:最简单的消息队列模型,包含一个生产者、一个队列和一个消费者。生产者直接将消息发送到队列,消费者从队列中接收消息。

  • 工作队列模式(Work Queues):使用默认的交换机,一个队列对应多个消费者,消息按轮询(Round-Robin)或公平分发(Fair Dispatch)分配给消费者,避免单个消费者过载。

  • 发布/订阅模式(Publish/Subscribe):使用 扇形交换机(Fanout Exchange)生产者将消息发送到交换机,交换机将消息广播到所有绑定的队列,每个消费者独立接收一份消息副本。

  • 路由模式(Routing):使用 直接交换机(Direct Exchange)生产者指定消息的 路由键(Routing Key),交换机根据路由键将消息精确匹配到绑定的队列

  • 主题模式(Topics):使用 主题交换机(Topic Exchange)路由键支持通配符匹配(* 匹配一个词,# 匹配多个词)。例如路由键 stock.usd.nyse 可被 *.nysestock.# 订阅。

  • 远程过程调用(RPC):通过消息队列实现远程调用。客户端发送请求消息时附带回调队列和唯一ID,服务端处理完成后将响应发送到回调队列,客户端通过ID匹配响应。

  • 发布者确认(Publisher Confirms):生产者发送消息后,RabbitMQ会异步返回确认(ACK)或未确认(NACK),确保消息成功到达交换机或队列。

工作队列模式(Work Queues)
  1. 并行处理能力

  • 多消费者竞争消费一个队列可绑定多个消费者,消息被并发处理消息只会被其中的一个消费者拿到。

  • 横向扩展:通过增加消费者数量,轻松应对高并发或大流量场景。

  1. 负载均衡机制

  • 轮询分发(Round-Robin)默认策略,均摊消息到所有消费者简单但可能因消费者性能差异导致负载不均。

  • 公平分发(Fair Dispatch):通过 prefetch_count 限制消费者同时处理的消息数,确保“能者多劳”,避免慢消费者堆积任务。

  1. 消息可靠性保障

  • ACK确认机制:消费者处理完成后需手动发送确认(ACK),若处理失败或消费者宕机,消息自动重新入队,确保任务不丢失。

  • 持久化支持:队列和消息均可设置为持久化(durable=true),防止RabbitMQ服务重启后数据丢失。

//================================生产端代码循环发送10次消息================================  
public class Producer {  public static final String QUEUE_NAME = "work_queue";  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  channel.queueDeclare(QUEUE_NAME,true,false,false,null);  for (int i = 1; i <= 10; i++) {  String body = i+"hello rabbitmq~~~";  channel.basicPublish("",QUEUE_NAME,null,body.getBytes());  }  channel.close();  connection.close();  }  }
 
//================================消费端代码竞争消息================================public class Consumer1/2 {  static final String QUEUE_NAME = "work_queue";  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  channel.queueDeclare(QUEUE_NAME,true,false,false,null);  Consumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("Consumer1 body:"+new String(body));  }  };  channel.basicConsume(QUEUE_NAME,true,consumer);  }  }

发布/订阅模式(Publish/Subscribe)
  1. 消息广播机制

  • 扇形交换机(Fanout Exchange)驱动生产者将消息发送到交换机,交换机会将消息无条件广播到所有与其绑定的队列,每个队列的消费者都能收到一份消息副本。

  • 一对多分发一条消息可被多个消费者同时接收,适用于需要广泛触达的场景(如系统通知、日志收集)。

//====================================生产者代码====================================
public class Producer {  public static void main(String[] args) throws Exception {  // 1、获取连接  Connection connection = ConnectionUtil.getConnection();  // 2、创建频道  Channel channel = connection.createChannel();  // 参数1. exchange:交换机名称  // 参数2. type:交换机类型  //     DIRECT("direct"):定向  //     FANOUT("fanout"):扇形(广播),发送消息到每一个与之绑定队列。  //     TOPIC("topic"):通配符的方式  //     HEADERS("headers"):参数匹配  // 参数3. durable:是否持久化  // 参数4. autoDelete:自动删除  // 参数5. internal:内部使用。一般false  // 参数6. arguments:其它参数  String exchangeName = "test_fanout";  // 3、创建交换机  channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);  // 4、创建队列  String queue1Name = "test_fanout_queue1";  String queue2Name = "test_fanout_queue2";  channel.queueDeclare(queue1Name,true,false,false,null);  channel.queueDeclare(queue2Name,true,false,false,null);  // 5、绑定队列和交换机  // 参数1. queue:队列名称  // 参数2. exchange:交换机名称  // 参数3. routingKey:路由键,绑定规则  //     如果交换机的类型为fanout,routingKey设置为""  channel.queueBind(queue1Name,exchangeName,"");  channel.queueBind(queue2Name,exchangeName,"");  String body = "日志信息:张三调用了findAll方法...日志级别:info...";  // 6、发送消息  channel.basicPublish(exchangeName,"",null,body.getBytes());  // 7、释放资源  channel.close();  connection.close();  }  }
 
//====================================消费者1代码===================================
public class Consumer1 {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String queue1Name = "test_fanout_queue1";  channel.queueDeclare(queue1Name,true,false,false,null);  Consumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("body:"+new String(body));  System.out.println("队列 1 消费者 1 将日志信息打印到控制台.....");  }  };  channel.basicConsume(queue1Name,true,consumer);  }  }
​
//====================================消费者2代码===================================
public class Consumer2 {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String queue2Name = "test_fanout_queue2";  channel.queueDeclare(queue2Name,true,false,false,null);  Consumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("body:"+new String(body));  System.out.println("队列 2 消费者 2 将日志信息打印到控制台.....");  }  };  channel.basicConsume(queue2Name,true,consumer);  }  }

路由模式(Routing)
  1. 基于路由键的精确分发

  • 直接交换机(Direct Exchange)驱动生产者发送消息时需指定路由键(Routing Key),交换机会将消息精确匹配到绑定相同路由键的队列。

  • 条件性路由:仅当队列绑定的路由键与消息的路由键完全一致时,消息才会被投递,实现按条件分发。

  1. 灵活的消息过滤

  • 多队列绑定不同路由键可为同一交换机绑定多个队列,每个队列声明不同的路由键(例如 errorinfowarning,实现消息分类处理。

  • 生产者可控性:生产者通过指定路由键决定消息的目标队列,无需消费者干预。

//================================生产者代码========================================  
public class Producer {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String exchangeName = "test_direct";  // 创建交换机  channel.exchangeDeclare(exchangeName,BuiltinExchangeType.DIRECT,true,false,false,null);  // 创建队列  String queue1Name = "test_direct_queue1";  String queue2Name = "test_direct_queue2";  // 声明(创建)队列  channel.queueDeclare(queue1Name,true,false,false,null);  channel.queueDeclare(queue2Name,true,false,false,null);  // 队列绑定交换机  // 队列1绑定error  channel.queueBind(queue1Name,exchangeName,"error");  // 队列2绑定info error warning  channel.queueBind(queue2Name,exchangeName,"info");  channel.queueBind(queue2Name,exchangeName,"error");  channel.queueBind(queue2Name,exchangeName,"warning");  String message = "日志信息:张三调用了delete方法.错误了,日志级别warning";  // 发送消息  channel.basicPublish(exchangeName,"warning",null,message.getBytes());  System.out.println(message);  // 释放资源  channel.close();  connection.close();  }  }
 
//===============================消费者1代码========================================
public class Consumer1 {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String queue1Name = "test_direct_queue1";  channel.queueDeclare(queue1Name,true,false,false,null);  Consumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("body:"+new String(body));  System.out.println("Consumer1 将日志信息打印到控制台.....");  }  };  channel.basicConsume(queue1Name,true,consumer);  }  }
​
//===============================消费者2代码========================================
public class Consumer2 {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String queue2Name = "test_direct_queue2";  channel.queueDeclare(queue2Name,true,false,false,null);  Consumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("body:"+new String(body));  System.out.println("Consumer2 将日志信息存储到数据库.....");  }  };  channel.basicConsume(queue2Name,true,consumer);  }  }

主题模式(Topics)
  1. 基于通配符的灵活路由

  • 主题交换机(Topic Exchange)驱动:生产者发送消息时指定带层级的路由键(Routing Key,如 order.europe.paid),消费者通过绑定键(Binding Key)使用通配符* 匹配一个词,# 匹配零或多个词)订阅消息。

    • 示例:绑定键 *.europe.* 可匹配 order.europe.paidshipment.europe.delayed

    • 绑定键 stock.# 可匹配 stock.usd.nysestock.eur.london.close

  • 多维度匹配支持复杂的分层路由逻辑,适用于需要按多条件分类的场景。

  1. 高度动态的消息过滤

  • 灵活订阅:消费者可动态定义绑定键的通配规则,按需订阅特定模式的消息,无需修改生产者逻辑。

  • 精准与模糊匹配结合既能精确匹配固定路由键,也能通过通配符覆盖一类消息。

//================================生产者代码========================================
public class Producer {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String exchangeName = "test_topic";  channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);  String queue1Name = "test_topic_queue1";  String queue2Name = "test_topic_queue2";  channel.queueDeclare(queue1Name,true,false,false,null);  channel.queueDeclare(queue2Name,true,false,false,null);  // 绑定队列和交换机  // 参数1. queue:队列名称  // 参数2. exchange:交换机名称  // 参数3. routingKey:路由键,绑定规则  //      如果交换机的类型为fanout ,routingKey设置为""  // routing key 常用格式:系统的名称.日志的级别。  // 需求: 所有error级别的日志存入数据库,所有order系统的日志存入数据库  channel.queueBind(queue1Name,exchangeName,"#.error");  channel.queueBind(queue1Name,exchangeName,"order.*");  channel.queueBind(queue2Name,exchangeName,"*.*");  // 分别发送消息到队列:order.info、goods.info、goods.error  String body = "[所在系统:order][日志级别:info][日志内容:订单生成,保存成功]";  channel.basicPublish(exchangeName,"order.info",null,body.getBytes());  body = "[所在系统:goods][日志级别:info][日志内容:商品发布成功]";  channel.basicPublish(exchangeName,"goods.info",null,body.getBytes());  body = "[所在系统:goods][日志级别:error][日志内容:商品发布失败]";  channel.basicPublish(exchangeName,"goods.error",null,body.getBytes());  channel.close();  connection.close();  }  }
 
//================================消费者1代码=======================================
public class Consumer1 {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String QUEUE_NAME = "test_topic_queue1";  channel.queueDeclare(QUEUE_NAME,true,false,false,null);  Consumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("body:"+new String(body));  }  };  channel.basicConsume(QUEUE_NAME,true,consumer);  }  }
​
//================================消费者2代码=======================================
public class Consumer2 {  public static void main(String[] args) throws Exception {  Connection connection = ConnectionUtil.getConnection();  Channel channel = connection.createChannel();  String QUEUE_NAME = "test_topic_queue2";  channel.queueDeclare(QUEUE_NAME,true,false,false,null);  Consumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("body:"+new String(body));  }  };  channel.basicConsume(QUEUE_NAME,true,consumer);  }  }

相关文章:

RabbitMQ--基础篇

RabbitMQ 简介&#xff1a;RabbitMQ 是一种开源的消息队列中间件&#xff0c;你可以把它想象成一个高效的“邮局”。它专门负责在不同应用程序之间传递消息&#xff0c;让系统各部分能松耦合地协作 优势&#xff1a; 异步处理&#xff1a;比如用户注册后&#xff0c;主程序将发…...

ResNet残差神经网络的模型结构定义(pytorch实现)

ResNet残差神经网络的模型结构定义&#xff08;pytorch实现&#xff09; ResNet‑34 ResNet‑34的实现思路。核心在于&#xff1a; 定义残差块&#xff08;BasicBlock&#xff09;用 _make_layer 方法堆叠多个残差块按照 ResNet‑34 的通道和层数配置来搭建网络 import torch…...

如何使用极狐GitLab 软件包仓库功能托管 ruby?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 软件包库中的 Ruby gems (BASIC ALL) WARNING:Ruby gems 软件包库正在开发中&#xff0c;由于功能有限&#xff0c;尚未准备好…...

AI日报 · 2025年5月08日|Stripe发布全球首个支付AI基础模型

1、Stripe 发布支付领域专用 AI 基础模型及稳定币账户功能 Stripe 于5月7日在其年度 Sessions 大会上发布了全球首个专为支付领域打造的 AI 基础模型——“Payments Foundation Model”&#xff0c;该模型基于数百亿笔交易数据训练&#xff0c;能够捕捉每个支付中数百个传统模…...

React 笔记[1] hello world

React 笔记[1] hello world 明白了&#xff01;既然你已经安装了 Node.js&#xff0c;我们可以 从零开始搭建一个 React Tailwind CSS 的 Hello World 项目。我将一步步列出操作指令&#xff0c;你只需要在终端里依次执行。 ✅ 第一步&#xff1a;初始化项目 mkdir my-hello…...

好消息!PyCharm 社区版现已支持直接选择 WSL 终端为默认终端

在过去&#xff0c;PyCharm 社区版虽然提供了链接 Windows 子系统 Linux&#xff08;WSL&#xff09;终端的能力&#xff0c;但用户无法在设置中直接指定 WSL 为默认终端&#xff0c;这一功能仅限于专业版使用者。 而现在&#xff0c;在 PyCharm 2025.1.1 版本中&#xff0c;Je…...

基于redis的定时状态更新

基于redis的定时状态更新 下面是一个简单的示例&#xff0c;展示如何使用redis实现状态更新&#xff0c;从而满足在某些场景下&#xff0c;既需要频繁更新状态&#xff0c; 又需要保证状态的实时性。以及定时更新状态的需求。 示例说明 假设有一个剧目演出计划&#xff0c;确…...

[原创](现代Delphi 12指南):[macOS 64bit App开发]: 如何获取自身程序的所在的目录?

[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…...

服务器托管的常见问题

一、何谓IDC服务器托管服务? IDC服务器托管是指为了提高网站的访问速度&#xff0c;将您的服务器及相关设备托管到具有完善机房设施、高品质网络环境、丰富带宽资源和运营经验以及可对用户的网络和设备进行实时监控的网络数据中心内&#xff0c;以此使系统达到安全、可靠、稳定…...

使用Scrapeless Scraping Browser的自动化和网页抓取最佳实践

引言&#xff1a;人工智能时代浏览器自动化和数据收集的新范式 随着生成性人工智能、人工智能代理和数据密集型应用程序的快速崛起&#xff0c;浏览器正在从传统的“用户互动工具”演变为智能系统的“数据执行引擎”。在这一新范式中&#xff0c;许多任务不再依赖单一的API端点…...

电子电气架构 --- 如何有助于提安全性并减少事故

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...

【训练】Qwen2.5VL 多机多卡 Grounding Box定位

之前的相关文章&#xff1a; 【深度学习】LLaMA-Factory微调sft Qwen2-VL进行印章识别 https://www.dong-blog.fun/post/1661 使用LLaMA-Factory微调sft Qwen2-VL-7B-Instruct https://www.dong-blog.fun/post/1762 构建最新的LLaMA-Factory镜像 https://www.dong-blog.f…...

MYSQL的行级锁到底锁的是什么东西

MySQL 的行级锁是一种锁机制&#xff0c;它允许数据库在执行并发操作时&#xff0c;锁定表中的某一行数据而不是整张表。行级锁通过限制对特定行的访问&#xff0c;允许其他线程并发地访问表中的其他行&#xff0c;从而提高并发性和性能。 行级锁的锁定对象 行级锁锁定的是 行…...

图神经网络中的虚拟节点

1.虚拟节点 当我们使用节点来构成图结构时&#xff0c; regular node: 常规的节点即代表了某一个局部特征&#xff0c; 即局部节点特征。 virtual node&#xff1a; 普通的节点不同&#xff0c;有时会需要这样的一种特征&#xff0c; 该特征代表了该样本的全局信息&#xff0…...

关于多版本CUDA共存的研究,是否能一台机子装两个CUDA 版本并正常切换使用

我发现了一个很有意思的事 我装了11.8cuda再装12.3cuda结果我的11.8cuda还在&#xff0c;没被替换掉或者删掉 然后我打开我的环境发现它的环境除了cuda_path都没改 这样我就有个大胆的想法&#xff0c;如果我把cuda path换成11.8路径那是不是就能切换了 而且cuda_path 和 cuda_…...

el-table与echarts图形实现滚动联动

el-table与echarts图形滚动联动 效果图 实现思路 设计图滚动条位于表格下方&#xff0c;且echarts滚动不易获取当前展示数据到左侧的距离 故&#xff1a;通过监听表格的滚动实现联动 为了保持echarts的横坐标和表格的列基本保持对齐&#xff0c;用tdWidth标识单列表格的宽度…...

【Git】【commit】查看未推送的提交查看指定commit的修改内容合并不连续的commit

文章目录 1. 查看未推送的提交方法一 &#xff1a;git status方法二&#xff1a;git log方法三&#xff1a;git cherry方法四&#xff1a;git rev-list 2. 查看指定commit的修改方法一&#xff1a;git show方法二&#xff1a;git log方法三&#xff1a;git diff 3. 合并不连续的…...

C++GO语言微服务基础技术①

目录 01-项目简介 02-单体式架构 03-微服务优缺点 04-单体式和微服务区别 05-RPC简介 06-RPC使用步骤 07-注册RPC服务函数接口 08-绑定服务和调用方法函数接口 09-rpc服务端和客户端编码实现 10-json的rpc 11-rpc的封装 12-rpc封装小结 01-项目简介 # 单体式和微服…...

AI CUBE 使用指南 目标检测格式范例 AI cube 报错数据集不合规范,请清洗数据集

血的教训&#xff1a;labels.txt里面放1 2 3 4 ..也可以英文&#xff0c;不能有中文 教程&#xff1a;K230 借助 AICube部署AI 视觉模型 YOLO等教程_嘉楠 ai cube多标签分类-CSDN博客 | 目标检测范例&#xff1a; 不清楚不是数字行不行 这个id可以英文&#xff0c;你…...

vue中scss使用js的变量

一、前言 在项目开发中&#xff0c;很多时候会涉及到scss样式变量&#xff0c;正常定义方式 $primary-color: rgb(188, 0, 194);&#xff1b;使用时直接使用即可&#xff1a;color: $primary-color。但是&#xff0c;如果&#xff0c;这些变量是在js中定义的怎么办 二、实现 …...

QtGUI模块功能详细说明, 字体和文本渲染(四)

目录 一. 窗口和屏幕管理 二. 绘图和渲染 三. 图像处理 四. 字体和文本 1、核心概念 1.1、字体 (Font) 1.2、字形 (Glyph) 1.3、字符 (Character) 1.4、文本布局 (Text Layout) 1.5、文本渲染 (Text Rendering) 1.6、度量 (Metrics) 2、字体管理 2.1、QFont&#…...

计算机学习路线与编程语言选择(信息差)

——授人以鱼不如授人以渔 面向岗位学习&#xff01;到招聘网站看看有哪些岗位&#xff0c;看一看岗位职责、要求 牛客网&#xff08;计算机实习工作最好的网站&#xff09; boss直聘 确定岗位后&#xff08;如前端、后端&#xff09;&#xff0c;岗位需要什么语言&#xf…...

多环串级PID

文章目录 为什么要多环程序主函数内环外环 双环PID调参内环Kp调法Ki调法 外环Kp 以一定速度到达指定位置封装 为什么要多环 单环只能单一控制速度或者位置&#xff0c;如果想要同时控制多个量如速度&#xff0c;位置&#xff0c;角度&#xff0c;就需要多个PID 速度环一般PI…...

编写大模型Prompt提示词方法

明确目标和任务 // 调用LLM进行分析const prompt 你是一名严格而友好的英语口语评分官&#xff0c;专业背景包括语音学&#xff08;phonetics&#xff09;、二语习得&#xff08;SLA&#xff09;和自动语音识别&#xff08;ASR&#xff09;。你的任务是&#xff1a; ① 比对参…...

使用chrome浏览器截长图

如何使用chrome浏览器截长图&#xff1a; 使用chrome截取完整网页图片 第一步、按F12&#xff0c;开发者模式的布局按下图布局 第二步、按ctrlshiftp组合键&#xff0c;搜索“截图” &#xff0c;然后自动截图保存在下载目录&#xff08;右上角&#xff09;了。...

【MySQL】第二弹——MySQL表的增删改查(CURD))

文章目录 &#x1f393;一. CRUD&#x1f393;二. 新增(Create)&#x1f393;三. 查询(Rertieve)&#x1f4d6;1. 全列查询&#x1f4d6;2. 指定列查询&#x1f4d6;3. 查询带有表达式&#x1f4d6;4. 起别名查询(as )&#x1f4d6; 5. 去重查询(distinct)&#x1f4d6;6. 排序…...

Android NDK版本迭代与FFmpeg交叉编译完全指南

在Android开发中&#xff0c;使用NDK(Native Development Kit)进行原生代码开发是一项常见需求&#xff0c;特别是当我们需要集成FFmpeg这样的多媒体处理库时。本文将深入分析Android NDK的版本迭代分界线&#xff0c;详细讲解FFmpeg交叉编译的注意事项&#xff0c;并提供完整的…...

【Linux网络】Socket-UDP相关函数

socket() 函数 这个函数的作用是创建一个 Socket 文件描述符&#xff0c;在客户端和服务器都可以使用。 #include <sys/socket.h> int socket(int domain, int type, int protocol);参数&#xff1a; domain&#xff1a;指定协议族&#xff0c;例如 AF_INET 代表 IPv4 …...

最优化方法Python计算:有约束优化应用——线性Lasso回归预测器

实际应用中&#xff0c;特征维度 n n n通常远大于样本容量 m m m&#xff08; n ≪ m n\ll m n≪m&#xff09;&#xff0c;这种高维小样本场景下特征数据可能含有对标签数据 y i y_i yi​的取值不必要的成分&#xff0c;甚至是噪声。此时&#xff0c;我们希望回归模型中的优化…...

基础算法 —— 二分算法 【复习总结】

1. 简介 1.1 原理 二分算法&#xff0c;顾名思义&#xff0c;关键在于二分&#xff0c;当我们求解的目标具有二段性时&#xff0c;我们就可以使用二分算法&#xff1a; 先根据待查找区间中点位置&#xff0c;判断结果会在左侧还是右侧&#xff0c;接下来&#xff0c;舍弃一半…...

计算机网络常识:缓存、长短连接 网络初探、URL、客户端与服务端、域名操作 tcp 三次握手 四次挥手

缓存&#xff1a; 缓存是对cpu&#xff0c;内存的一个节约&#xff1a;节约的是网络带宽资源 节约服务器的性能 资源的每次下载和请求都会造成服务器的一个压力 减少网络对资源拉取的延迟 这个就是浏览器缓存的一个好处 表示这个html页面的返回是不要缓存的 忽略缓存 需要每次…...

OpenHarmony平台驱动开发(九),MIPI DSI

OpenHarmony平台驱动开发&#xff08;九&#xff09; MIPI DSI 概述 功能简介 DSI&#xff08;Display Serial Interface&#xff09;是由移动行业处理器接口联盟&#xff08;Mobile Industry Processor Interface (MIPI) Alliance&#xff09;制定的规范&#xff0c;旨在降…...

经济体制1

一&#xff0e;计划经济体制与市场经济体制 1.计划经济又称指令型经济&#xff0c;是对生产和资源分配以及产品消费事先进行计划的经济体制。 市场经济体制是指依靠市场手段对资源进行配置的经济体制 注意&#xff1a; 计划与市场都是调节经济的手段&#xff0c;都属于资源配…...

Spring AI 入门(持续更新)

介绍 Spring AI 是 Spring 项目中一个面向 AI 应用的模块&#xff0c;旨在通过集成开源框架、提供标准化的工具和便捷的开发体验&#xff0c;加速 AI 应用程序的构建和部署。 依赖 <!-- 基于 WebFlux 的响应式 SSE 传输 --> <dependency><groupId>org.spr…...

[ctfshow web入门] web58

信息收集 if(isset($_POST[c])){$c $_POST[c];eval($c); }else{highlight_file(__FILE__); }这麽简单&#xff1f; 解题 好吧&#xff0c;还是我想得太简单了 把system禁用了。不是参数过滤&#xff0c;而是直接禁用&#xff0c;不管是间接还是直接调用system都不行&#x…...

Python量化交易Backtrader技术指标的实现

一、Backtrader技术指标概览 (一)Backtrader内置指标的优势 Backtrader内置的技术指标具有以下优势: 多样性:涵盖了常见的移动平均线、相对强弱指数(RSI)、布林带等多种指标,满足了不同交易者的需求。易用性:通过简单的函数调用即可在策略中添加和使用这些指标,无需…...

蓝桥杯第十六届c组c++题目及个人理解

本篇文章只是部分题目的理解&#xff0c;代码和思路仅供参考&#xff0c;切勿当成正确答案&#xff0c;欢迎各位小伙伴在评论区与博主交流&#xff01; 题目&#xff1a;2025 题目解析 核心提取 要求的数中至少有1个0、2个2、1个5 代码展示 #include<iostream> #incl…...

ARM 芯片上移植 Ubuntu 操作系统详细步骤

一、准备工作 &#xff08;一&#xff09;硬件准备 ARM 开发板&#xff1a;确保 ARM 开发板的型号与 Ubuntu 官方支持的 ARM 架构兼容&#xff0c;常见的 ARM 架构有 ARMv7、ARMv8 等。例如树莓派系列开发板&#xff0c;广泛用于 ARM 系统移植&#xff0c;其采用 ARM 架构。存…...

能耗优化新引擎:EIOT平台助力企业降本增效

安科瑞顾强 数字化转型的背景下&#xff0c;能源管理正加速向智能化、远程化方向演进。安科瑞电气推出的EIOT托管平台及ADW300系列4G无线计量仪表&#xff0c;通过云端技术与无线通信的深度融合&#xff0c;为用户打造了高效、便捷的远程能源监测与管理体系&#xff0c;助力企…...

录播课视觉包装与转化率提升指南

1. 封面设计黄金法则 1.1 程序员审美三要素 极客风配色方案 主色&#xff1a;深空灰(#2D2D2D) 代码蓝(#007BFF) 点缀色&#xff1a;终端绿(#28A745) 警告黄(#FFC107) 信息密度控制 核心标语≤9字&#xff08;如&#xff1a;"3天攻克分布式事务"&#xff09; 技…...

Solidity语言基础:区块链智能合约开发入门指南

一、Solidity概述 Solidity是以太坊生态系统中最重要的智能合约编程语言&#xff0c;由Gavin Wood于2014年提出。作为面向合约的高级语言&#xff0c;它结合了JavaScript、Python和C的语法特点&#xff0c;专为在以太坊虚拟机&#xff08;EVM&#xff09;上运行而设计。 核心…...

QMK开发环境搭建指南:Eclipse和VS Code详解

QMK开发环境搭建指南&#xff1a;Eclipse和VS Code详解 前言 各位键盘DIY爱好者们&#xff0c;今天跟大家分享如何搭建QMK固件开发环境。无论你是想定制自己的客制化键盘固件&#xff0c;还是对开源键盘固件开发感兴趣&#xff0c;这篇教程都能帮你搞定开发环境配置。本文将详…...

Python pandas 向excel追加数据,不覆盖之前的数据

最近突然看了一下pandas向excel追加数据的方法&#xff0c;发现有很多人出了一些馊主意&#xff1b; 比如用concat,append等方法&#xff0c;这种方法的会先将旧数据df_1读取到内存&#xff0c;再把新数据df_2与旧的合并&#xff0c;形成df_new,再覆盖写入&#xff0c;消耗和速…...

spring中RequestContextHolder

1、在 Spring 框架中&#xff0c; RequestAttributes attributes RequestContextHolder.getRequestAttributes(); 是获取当前请求上下文的核心方法。以下是其关键要点及注意事项&#xff1a; ‌一、核心机制‌ ‌作用原理‌ 通过 ThreadLocal 存储当前线程的请求属性对象 …...

Kotlin 遍历

在 Kotlin 中&#xff0c;遍历&#xff08;迭代&#xff09;是操作集合、数组、范围&#xff08;Range&#xff09;等数据结构的常见需求。Kotlin 提供了多种遍历方式&#xff0c;语法简洁且功能强大。以下是不同场景下的遍历方法总结&#xff0c;附代码示例&#xff1a; 一、…...

Ubuntu Linux系统配置账号无密码sudo

在Linux系统中&#xff0c;配置无密码sudo可以通过修改sudoers文件来实现。以下是具体的配置步骤 一、编辑sudoers文件 输入sudo visudo命令来编辑sudo的配置文件。visudo是一个专门用于编辑sudoers文件的命令&#xff0c;它会在保存前检查语法错误&#xff0c;从而防止可能的…...

C# NX二次开发:判断两个体是否干涉和获取系统日志的UFUN函数

大家好&#xff0c;今天要讲关于如何判断两个体是否干涉和获取系统日志的UFUN函数。 &#xff08;1&#xff09;UF_MODL_check_interference&#xff1a;这个函数的定义为根据单个目标体检查每个指定的工具体是否有干扰。 Defined in: uf_modl.h Overview Checks each sp…...

若依项目图片显示问题

图片显示异常问题 路径配置问题&#xff1a;前端图片路径配置错误&#xff0c;最初使用相对路径且未从根目录开始解析&#xff0c;导致浏览器根据当前页面 URL 解析路径出错。例如在用户信息展示页面&#xff0c;若当前页面 URL 为http://localhost:8088/user/profile&#xff…...

线索二叉树

一 概念 线索二叉树&#xff08;Threaded Binary Tree&#xff09;是一种对二叉树的优化结构&#xff0c;主要解决传统二叉树遍历时需要借助栈或递归&#xff08;额外空间开销&#xff09;的问题。通过利用节点中的空指针&#xff08;nullptr&#xff09;存储遍历过程中的前驱…...

Git查看某个commit的改动

在Git中查看特定commit的改动有多种方法&#xff0c;下面是几种常用的命令行方式&#xff1a; 1. 使用 git show 命令 这是最常用的方法&#xff0c;直接显示某个commit的详细信息和改动&#xff1a; git show <commit-hash> 例如&#xff1a; git show abc1234 也可…...