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

RabbitMQ(一) - 基本结构、SpringBoot整合RabbitMQ、工作队列、发布订阅、直接、主题交换机模式

RabbitMQ结构

  • Publisher : 生产者

  • Queue: 存储消息的容器队列;

  • Consumer:消费者

  • Connection:消费者与消息服务的TCP连接

  • Channel:信道,是TCP里面的虚拟连接。例如:电缆相当于TCP,信道是一条独立光纤束,一条TCP连接上创建多少条信道是没有限制的。TCP一旦打开,就会出AMQP信道。无论是发布消息,接收消息,订阅队列,这些动作都是通过信道完成的。
    Broker: 一台消息服务就是一个Broker;

  • Exchange:交换机、负责接收生产者的消息,转发到队列中、交换机和队列通过路由键绑定、可以理解为每个队列都有自己的名称;
    在这里插入图片描述

SpringBoot整合RabbitMQ

  • Queue
    • 消息存放于队列中, 若是RabbitMQ挂了,则消息会丢失,因此要开启持久化, 将durable设置为true,
    • 若是没有消费者消费该队列,则该队列会自动删除, 因此需要将autoDelete参数设置为false;
    public Queue(String name) {//  队列名称, 是否持久化,是否独占, 是否自动删除this(name, true, false, false);}
  • @RabbitListener
@RabbitListener(bindings=@QueueBinding(value= @Queue(value="${mq.config.queue.info}",autoDelete="true"),exchange=@Exchange(value="${mq.config.exchange}",type=ExchangeTypes.DIRECT),key="${mq.config.queue.info.routing.key}"))

用来标记消费者;exchange表示交换器信息、类型;bindings表示监听器要绑定的队列、以及队列信息;
key:代表交换机和队列通过key绑定的;

  • AmqpTemplate / RabbitTempldate:
    生产者通过依赖此工具类发送消息;

先安装RabbitMQ,创建SpringBoot项目,修改配置

# 应用名称
spring.application.name=boolfilter# 应用服务 WEB 访问端口
server.port=8080spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

入门级别程序

发送hello world程序;
在这里插入图片描述
生产者:

public class Tut1Sender {@Autowiredprivate RabbitTemplate template;@Autowiredprivate Queue queue;@Scheduled(fixedDelay = 1000, initialDelay = 500)public void send() {String message = "Hello World!";this.template.convertAndSend(queue.getName(), message);System.out.println(" [x] Sent '" + message + "'");}
}

消费者:

@RabbitListener(queues = "hello")
public class Tut1Receiver {@RabbitHandlerpublic void receive(String in) {System.out.println(" [x] Received '" + in + "'");}
}

将生产者、消费者注入容器;

@Configuration
@EnableScheduling
public class Tut1Config {@Beanpublic Queue hello() {return new Queue("hello");}@Beanpublic Tut1Receiver receiver() {return new Tut1Receiver();}@Beanpublic Tut1Sender sender() {return new Tut1Sender();}
}

运行结果:

[x] Sent ‘Hello World!’
[x] Received ‘Hello World!’
[x] Sent ‘Hello World!’
[x] Received ‘Hello World!’
[x] Sent ‘Hello World!’

工作队列

主要思想是避免 立即执行资源密集型任务,必须等待它要完成。相反,我们将任务安排在以后完成。我们将任务封装为消息并将其发送到队列。正在运行的工作进程 在后台将弹出任务并最终执行工作
在这里插入图片描述
生产者:

public class Tut2Sender {@Autowiredprivate RabbitTemplate template;@Autowiredprivate Queue queue;AtomicInteger dots = new AtomicInteger(0);AtomicInteger count = new AtomicInteger(0);@Scheduled(fixedDelay = 1000, initialDelay = 500)public void send() {`在这里插入代码片`StringBuilder builder = new StringBuilder("Hello");if (dots.incrementAndGet() == 4) {dots.set(1);}for (int i = 0; i < dots.get(); i++) {builder.append('.');}builder.append(count.incrementAndGet());String message = builder.toString();template.convertAndSend(queue.getName(), message);System.out.println(" [x] Sent '" + message + "'");}}

消费者:

@RabbitListener(queues = "hello")
public class Tut2Receiver {private final int instance;public Tut2Receiver(int i) {this.instance = i;}@RabbitHandlerpublic void receive(String in) throws InterruptedException {StopWatch watch = new StopWatch();watch.start();System.out.println("instance " + this.instance +" [x] Received '" + in + "'");doWork(in);watch.stop();System.out.println("instance " + this.instance +" [x] Done in " + watch.getTotalTimeSeconds() + "s");}private void doWork(String in) throws InterruptedException {for (char ch : in.toCharArray()) {if (ch == '.') {Thread.sleep(1000);}}}
}

队列、生产者、消费者注入容器:

@Configuration
public class Tut2Config {@Beanpublic Queue hello() {return new Queue("hello");}private static class ReceiverConfig {@Beanpublic Tut2Receiver receiver1() {return new Tut2Receiver(1);}@Beanpublic Tut2Receiver receiver2() {return new Tut2Receiver(2);}}@Beanpublic Tut2Sender sender() {return new Tut2Sender();}
}

运行结果:

[x] Sent ‘Hello.1’
instance 1 [x] Received ‘Hello.1’
[x] Sent ‘Hello…2’
instance 2 [x] Received ‘Hello…2’
instance 1 [x] Done in 1.0062309s
[x] Sent ‘Hello…3’
instance 1 [x] Received ‘Hello…3’
instance 2 [x] Done in 2.0085791s
[x] Sent ‘Hello.4’
instance 2 [x] Received ‘Hello.4’

消息确认

  • SpringBoot整合RabbitMQ代码中,若消费者消费出现异常,则会重新进入队列, 一般生产环境中,是要有重试机制的;
  • 若是要关闭重试机制、则设置defaultRequeueRejected=false, 或者抛出AmqpRejectAndDontRequeueException异常,这样框架会帮我们自动提交确认channel.basicAck()
  • 重试机制也会存在问题、若是消费者服务关闭、则消息会不断重新入队、导致RabbitMQ内存最终爆满宕机;
  • 消息的ACK确认机制默认是打开的;如果忘记了ACK,后果很严重,当Consumer退出时,消息会一直重新分发,然后RabbitMq会占用越来越多的内存,由于RabbitMq会长时间运行,出现“内存泄露”是致命的

异常处理方案:

  • 使用try-catch捕捉
  • 使用重试机制、超过一定次数、则丢弃消息或放入死信队列;

spring.rabbitmq.listener.retry.max-attempts=5 //重试超过5次,消息丢弃;

公平调度与循环调度

  • 默认情况下,RabbitMQ 会将每条消息发送给下一个消费者。平均而言,每个消费者将获得相同数量的 消息。这种分发消息的方式称为轮询。 在这种模式下,调度不一定完全按照我们想要的方式工作。 若是存在两台机器,一台性能好、一台性能差, 而RabbitMQ对此一无所知,仍然会调度 消息均匀。发生这种情况是因为 RabbitMQ 只是在消息时调度消息 进入队列。它不看未确认的数量 面向消费者的消息。它只是盲目地发送每 n 条消息 给第 n 个消费者,这就导致了一台机器特别忙碌、一台机器空闲;

  • “公平调度”是Spring AMQP的默认配置。Consumer可以向服务器声明一个prefetchCount, 表示轮到自己时、自己可处理多少消息;这样RabbitMQ转发消息给消费者时、会先看Consumer正在处理的消息数量是否达到了prefetchCount, 若已达到该值,则发给其他的Consumer;

发布/订阅

在这里插入图片描述
特点:一条消息同时会被所有消费者消息;X是交换机(Exchange);交换机和队列进行绑定(Binding)
交换机负责接收生产者发送的消息,再转发消息到队列中;实现了生产者与队列的解耦;

RabbitMQ 中消息传递模型的核心思想是生产者 从不将任何消息直接发送到队列

示例1 : 广播匿名队列

发送者:

public class Tut3Sender {@Autowiredprivate RabbitTemplate template;@Autowiredprivate FanoutExchange fanout;AtomicInteger dots = new AtomicInteger(0);AtomicInteger count = new AtomicInteger(0);@Scheduled(fixedDelay = 1000, initialDelay = 500)public void send() {StringBuilder builder = new StringBuilder("Hello");if (dots.getAndIncrement() == 3) {dots.set(1);}for (int i = 0; i < dots.get(); i++) {builder.append('.');}builder.append(count.incrementAndGet());String message = builder.toString();template.convertAndSend(fanout.getName(), "", message);System.out.println(" [x] Sent '" + message + "'");}}

消费者:

public class Tut3Receiver {@RabbitListener(queues = "#{autoDeleteQueue1.name}")public void receive1(String in) throws InterruptedException {receive(in, 1);}@RabbitListener(queues = "#{autoDeleteQueue2.name}")public void receive2(String in) throws InterruptedException {receive(in, 2);}public void receive(String in, int receiver) throws InterruptedException {StopWatch watch = new StopWatch();watch.start();System.out.println("instance " + receiver + " [x] Received '" + in + "'");doWork(in);watch.stop();System.out.println("instance " + receiver + " [x] Done in "+ watch.getTotalTimeSeconds() + "s");}private void doWork(String in) throws InterruptedException {for (char ch : in.toCharArray()) {if (ch == '.') {Thread.sleep(1000);}}}}

交换机、匿名队列、绑定,生产者、消费者注入容器;

public class Tut3Config {@Beanpublic FanoutExchange fanout() {return new FanoutExchange("tut.fanout");}private static class ReceiverConfig {@Beanpublic Queue autoDeleteQueue1() {return new AnonymousQueue();}@Beanpublic Queue autoDeleteQueue2() {return new AnonymousQueue();}@Beanpublic Binding binding1(FanoutExchange fanout,Queue autoDeleteQueue1) {return BindingBuilder.bind(autoDeleteQueue1).to(fanout);}@Beanpublic Binding binding2(FanoutExchange fanout,Queue autoDeleteQueue2) {return BindingBuilder.bind(autoDeleteQueue2).to(fanout);}@Beanpublic Tut3Receiver receiver() {return new Tut3Receiver();}}@Beanpublic Tut3Sender sender() {return new Tut3Sender();}
}

运行结果:

instance 1 [x] Received 'Hello.1'
instance 2 [x] Received 'Hello.1'
instance 2 [x] Done in 1.0057994s
instance 1 [x] Done in 1.0058073s
....

模拟Spring容器发布ContextRefreshedEvent事件

通常情况下,业务开发中,经常会监听该事件做扩展,例如初始化数据, 打印日志等等;
生产者:

public class AppContextSender {@AutowiredRabbitTemplate rabbitTemplate;@Scheduled(fixedDelay = 1000, initialDelay = 500)public void publishContextRefreshEvent() {rabbitTemplate.convertAndSend("contextRefreshedExchange", "", "publish refreshed event");}
}

消费者:

@RabbitListener(queues = {"initQueue"})
public class InitContextRefreshedConsumer {@RabbitHandlerpublic void consum(String in) {System.out.println("init :"+in);}
}@RabbitListener(queues = "logQueue")
public class LogContextRefreshedConsumer {@RabbitHandlerpublic void consum(String in) {System.out.println("log : "+in);}
}

交换机、队列、绑定、生产者、消费者注入容器:

@Configuration
public class ContextRefreshedConfig {@Beanpublic FanoutExchange contextRefreshedExchange(){return new FanoutExchange("contextRefreshedExchange");}@Beanpublic AppContextSender appContextSender() {return new AppContextSender();}public static class ConsumerConfig {@Beanpublic Queue initQueue() {return new Queue("initQueue");}@Beanpublic Queue logQueue() {return new Queue("logQueue");}@Beanpublic Binding initBinding(Queue initQueue, FanoutExchange contextRefreshedExchange) {return BindingBuilder.bind(initQueue).to(contextRefreshedExchange);}@Beanpublic Binding logBinding(Queue logQueue, FanoutExchange contextRefreshedExchange) {return BindingBuilder.bind(logQueue).to(contextRefreshedExchange);}@Beanpublic InitContextRefreshedConsumer initContextRefreshedConsumer() {return new InitContextRefreshedConsumer();}@Beanpublic LogContextRefreshedConsumer logContextRefreshedConsumer() {return new LogContextRefreshedConsumer();}}}

log : publish refreshed event
init :publish refreshed event
log : publish refreshed event
init :publish refreshed event

Direct直接模式

  • 交换器绑定多个队列,每个绑定关系有自己的路由键;
  • 之前业务开发中、有一个交换机、绑定了两个队列,一个队列用来发送邮件,一个队列用来发送短信, 像广播模式下,如果只想发邮件,则没法t做到,使用direct模式和工作模式则可以做到, 最后使用了direct

在这里插入图片描述
生产者:

public class BaseServiceSender {@Autowiredprivate RabbitTemplate template;@Autowiredprivate DirectExchange messageExchange;AtomicInteger index = new AtomicInteger(0);AtomicInteger count = new AtomicInteger(0);private final String[] keys = {"sms", "mail"};@Scheduled(fixedDelay = 1000, initialDelay = 500)public void send() {//短信String sms = "{userName: xxx; phone:xxx}";template.convertAndSend(messageExchange.getName(), "sms", sms);//邮件String mail = "{userName: xxx; mail:xxx}";template.convertAndSend(messageExchange.getName(), "mail", mail);}
}

消费者:

@RabbitListener(queues = "mailQueue")
public class MailConsumer {@RabbitHandlerpublic void consum(String in) {System.out.println("send mail : " + in);}
}@RabbitListener(queues = "smsQueue")
public class SmsConsumer {@RabbitHandlerpublic void consum(String in) {System.out.println("send sms : " + in);}
}

交换机、队列,绑定、消费者,生产者注入容器:

@Configuration
public class DirectConfig {@Beanpublic DirectExchange messageExchange() {return new DirectExchange("messageExchange");}@Beanpublic BaseServiceSender baseServiceSender() {return new BaseServiceSender();}public static class ConsumerGroup {@Beanpublic MailConsumer mailConsumer() {return new MailConsumer();}@Beanpublic SmsConsumer smsConsumer() {return new SmsConsumer();}@Beanpublic Queue mailQueue() {return new Queue("mailQueue");}@Beanpublic Queue smsQueue() {return new Queue("smsQueue");}@Beanpublic Binding smsBinding(DirectExchange messageExchange, Queue smsQueue){return BindingBuilder.bind(smsQueue).to(messageExchange).with("sms");}@Beanpublic Binding mailBinding(DirectExchange messageExchange, Queue mailQueue){return BindingBuilder.bind(mailQueue).to(messageExchange).with("mail");}}
}

运行结果

send mail : {userName: xxx; mail:xxx}
send sms : {userName: xxx; phone:xxx}
send sms : {userName: xxx; phone:xxx}
send mail : {userName: xxx; mail:xxx}

Topic主题模式

  • 发送到主题交换的消息不能有任意routing_key
    • 它必须是单词列表,由点分隔。这 单词可以是任何东西,一些有效的路由密钥示例: “stock.usd.nyse”, “nyse.vmw”, “quick.orange.rabbit”。可以有 路由密钥中随心所欲地包含多个单词,最多可达 255 个 字节。
  • 绑定密钥也必须采用相同的形式。主题交换背后的逻辑类似于直接交换 - 发送的消息带有 特定的路由键将被传递到所有队列 绑定匹配的绑定键
  • *(星号)可以代替一个词。
  • #(哈希)可以替换零个或多个单词。

在这里插入图片描述
若是消息指定的路由键为"xxx.orange.xxx", 则会匹配到Q1, 若是"lazy.xxx.xx"则是Q2;

生产者:

public class Tut5Sender {@Autowiredprivate RabbitTemplate template;@Autowiredprivate TopicExchange topic;AtomicInteger index = new AtomicInteger(0);AtomicInteger count = new AtomicInteger(0);private final String[] keys = {"quick.orange.rabbit", "lazy.orange.elephant", "quick.orange.fox","lazy.brown.fox", "lazy.pink.rabbit", "quick.brown.fox"};@Scheduled(fixedDelay = 1000, initialDelay = 500)public void send() {StringBuilder builder = new StringBuilder("Hello to ");if (this.index.incrementAndGet() == keys.length) {this.index.set(0);}String key = keys[this.index.get()];builder.append(key).append(' ');builder.append(this.count.incrementAndGet());String message = builder.toString();template.convertAndSend(topic.getName(), key, message);System.out.println(" [x] Sent '" + message + "'");}}

消费者:

public class Tut5Receiver {@RabbitListener(queues = "#{autoDeleteQueue1.name}")public void receive1(String in) throws InterruptedException {receive(in, 1);}@RabbitListener(queues = "#{autoDeleteQueue2.name}")public void receive2(String in) throws InterruptedException {receive(in, 2);}public void receive(String in, int receiver) throwsInterruptedException {StopWatch watch = new StopWatch();watch.start();System.out.println("instance " + receiver + " [x] Received '"+ in + "'");doWork(in);watch.stop();System.out.println("instance " + receiver + " [x] Done in "+ watch.getTotalTimeSeconds() + "s");}private void doWork(String in) throws InterruptedException {for (char ch : in.toCharArray()) {if (ch == '.') {Thread.sleep(1000);}}}
}

交换器,队列,绑定、生产者,消费者注入容器:

@Configuration
public class Tut5Config {@Beanpublic TopicExchange topic() {return new TopicExchange("tut.topic");}private static class ReceiverConfig {@Beanpublic Tut5Receiver receiver() {return new Tut5Receiver();}@Beanpublic Queue autoDeleteQueue1() {return new AnonymousQueue();}@Beanpublic Queue autoDeleteQueue2() {return new AnonymousQueue();}@Beanpublic Binding binding1a(TopicExchange topic,Queue autoDeleteQueue1) {return BindingBuilder.bind(autoDeleteQueue1).to(topic).with("*.orange.*");}@Beanpublic Binding binding1b(TopicExchange topic,Queue autoDeleteQueue1) {return BindingBuilder.bind(autoDeleteQueue1).to(topic).with("*.*.rabbit");}@Beanpublic Binding binding2a(TopicExchange topic,Queue autoDeleteQueue2) {return BindingBuilder.bind(autoDeleteQueue2).to(topic).with("lazy.#");}}@Beanpublic Tut5Sender sender() {return new Tut5Sender();}}

运行结果:

[x] Sent ‘Hello to lazy.orange.elephant 1’
instance 2 [x] Received ‘Hello to lazy.orange.elephant 1’
instance 1 [x] Received ‘Hello to lazy.orange.elephant 1’
[x] Sent ‘Hello to quick.orange.fox 2’
[x] Sent ‘Hello to lazy.brown.fox 3’
instance 1 [x] Done in 2.0110456s

RPC远程过程调用

RabbitMQ也实现了RPC的功能,但是业务开发中,根本没有使用场景,RPC要么使用Dubbo, 要么使用OpenFeign, 使用RabbitMQ做RPC的信息,目前都没有看到;

总结

  • 就目前来说、工作队列、发布订阅两个模式,业务开发中会使用到,其他的消息场景很少见。
  • 底层是基于RabbitMQ-client做的封装出RabbitTempldate使用;除非远古项目,否则不推荐使用RabbitMQ-Client原生API写,太费时间了。我写了一会就放弃了

相关文章:

RabbitMQ(一) - 基本结构、SpringBoot整合RabbitMQ、工作队列、发布订阅、直接、主题交换机模式

RabbitMQ结构 Publisher &#xff1a; 生产者 Queue: 存储消息的容器队列&#xff1b; Consumer:消费者 Connection&#xff1a;消费者与消息服务的TCP连接 Channel:信道&#xff0c;是TCP里面的虚拟连接。例如&#xff1a;电缆相当于TCP&#xff0c;信道是一条独立光纤束&…...

涉及IMU的专业术语

文章目录 零偏维纳过程/布朗运动随机游走航迹推算 零偏 IMU&#xff08;惯性测量单元&#xff09;是一种用于测量物体在空间中的加速度和角速度的装置。它通常由加速度计和陀螺仪组成&#xff0c;这些传感器可以帮助确定物体的运动状态和方向。 在IMU中&#xff0c;“零偏”&…...

二维数组对角线判断

二维数组对角线判断 对于两个点&#xff08;x1, y1)和(x2, y2)。如何判断二者是否在同一条正对角线&#xff0c;反对角线&#xff0c;或者正或反对角线上&#xff1f; 正对角线判断 x2-x1 y2 -y1 证明&#xff1a;任意一点&#xff08;x1k, y1k)&#xff0c;&#xff08;k…...

数据可视化(六)多个子图及seaborn使用

1.多个子图绘制 #绘制多个子图 #subplot&#xff08;*args&#xff0c;**kwargs&#xff09; 每个subplot函数只能绘制一个子图 #subplots&#xff08;nrows&#xff0c;ncols&#xff09; #fig_add_subplot(行&#xff0c;列&#xff0c;区域) #绘制子图第一种方式 plt.subp…...

opencv-34 图像平滑处理-双边滤波cv2.bilateralFilter()

双边滤波&#xff08;BilateralFiltering&#xff09;是一种图像处理滤波技术&#xff0c;用于平滑图像并同时保留边缘信息。与其他传统的线性滤波方法不同&#xff0c;双边滤波在考虑像素之间的空间距离之外&#xff0c;还考虑了像素之间的灰度值相似性。这使得双边滤波能够有…...

Leetcode 268. Missing Number

Problem Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. Algorithm Sum all the numbers as x x x and use n ( n 1 ) 2 − x \frac{n(n1)}{2} - x 2n(n1)​−x. Code …...

MybatisPlus实战笔记

概述 Mybatis支持定制化SQL、存储过程以及高级映射&#xff0c;避免几乎所有的 JDBC 代码和手动设置参数以及获取结果集。可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将接口和Java的POJO映射成数据库中的记录。 缺点&#xff1a; SQL工作量很大&#xff0c;尤…...

Android Studio 报错:Failed to create Jar file xxxxx.jar

通过分析&#xff0c;新下载的项目没有project/gradle目录&#xff0c;故通过其他项目复制到当前项目&#xff0c;就解决了该问题。 同时也出现了新的问题 Unable to start the daemon process.The project uses Gradle 4.1 which is incompatible with Java 11 or newer.原因…...

Django实现音乐网站 ⑸

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是配置媒体资源设置。 目录 配置介绍 设置媒体资源 创建媒体资源目录 修改settings.py 注册媒体资源路由 总结 配置介绍 静态资源是指项目配置的js/css/image等系统常用文件。对于一些经常变动的资源&#x…...

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)七:工作台界面实现

一、本章内容 本章实现工作台界面相关内容,包括echart框架引入,mock框架引入等,实现工作台界面框架搭建,数据加载。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 基于VUE3+Layui从头搭建通用后台管理系统合集-工作台界面布局实现 五、…...

前端vue uni-app自定义精美海报生成组件

在当前技术飞速发展的时代&#xff0c;软件开发的复杂度也在不断提高。传统的开发方式往往将一个系统做成整块应用&#xff0c;一个小的改动或者一个小功能的增加都可能引起整体逻辑的修改&#xff0c;从而造成牵一发而动全身的情况。为了解决这个问题&#xff0c;组件化开发逐…...

高通滤波器,低通滤波器

1.高通滤波器是根据像素与邻近像素的亮度差值来提升该像素的亮度。 import cv2 import numpy as np from scipy import ndimagekernel_3_3 np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]) print(kernel_3_3) kernel_5_5 np.array([[-1,-1,-1,-1,-1],[-1,1,2,1,-1],[-1,2,4,2,-…...

机器学习深度学习——卷积的多输入多输出通道

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——从全连接层到卷积 &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章对你们有所帮…...

HTML5中Canvas学习笔记:Canvas

目录 一、HTML中Canvas画图strokeStyle 和 fillStyle 的区别是什么&#xff1f; 二、如何设置一幅canvas图中某个颜色透明&#xff1f; 三、H5 canvas中strokeRect参数如果是小数&#xff0c;如何处理&#xff1f; 四、H5 Canvas中如何画圆角矩形框&#xff1f; 一、HTML中…...

Windows安装子系统Linux

Windows安装子系统(Linux ubuntu&#xff09; 安装条件步骤1.安装WSL命令2.设置Linux用户名和密码3.写个简单的.c程序看看4.如何互传文件 安装条件 Windows 10版本2004及更高的版本才能安装。 步骤 1.安装WSL命令 我们可以使用WSL来安装子系统 Linux ubuntu(默认是这个)。 …...

C 语言的 pow() 函数

作用: Calculates x raised to the power of y. 函数原型: double pow( double x, double y ); Required Header: <math.h> Compatibility: ANSI Return Value pow returns the value of x y x^{y} xy. No error message is printed on overflow or underflow. Paramete…...

socket 基础

Socket是什么呢&#xff1f; ① Socket通常也称作“套接字”&#xff0c;用于描述IP地址和端口&#xff0c;是一个通信链的句柄。应用程序通常通过“套接字”向网络发出请求或者应答网络请求。 ② Socket是连接运行在网络上的两个程序间的双向通信的端点。 ③ 网络通讯其实指…...

JMeter(二十五)、一些概念的理解---90%响应时间、事务、并发

Jmeter中一些概念的理解——90%响应时间、事务、并发 一、90%响应时间(参考虫师博客) 90%Line 一组数由小到大进行排列,找到他的第90%个数(假如是12),那么这个数组中有90%的数将小于等于12 。 用在性能测试的响应时间,也就是90%请求响应时间不会超过12 秒。 例如:…...

直播课 | 大橡科技研发总监丁端尘博士“类器官芯片技术在新药研发中的应用”

从类器官到类器官芯片&#xff0c;正在生物科学领域大放异彩。 药物研发需要新方法 众所周知&#xff0c;一款新药是一个风险大、周期长、成本高的艰难历程&#xff0c;国际上有一个传统的“双十”说法——10年时间&#xff0c;10亿美金&#xff0c;才可能成功研发出一款新药…...

Python中的PDF文本提取:使用fitz和wxPython库(带进度条)

引言&#xff1a; 处理大量PDF文档的文本提取任务可能是一项繁琐的工作。本文将介绍一个使用Python编写的工具&#xff0c;可通过简单的操作一键提取大量PDF文档中的文本内容&#xff0c;极大地提高工作效率。 import wx import pathlib import fitzclass PDFExtractor(wx.Fr…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...