RabbitMQ 79b5ad38df29400fa52ef0085a14b02f

RabbitMQ

一、什么是消息队列


消息队列可以看作是一个存放消息的容器,其中,生产者负责生产数据到消息队列中,而消费者负责消费数据。消息队列是分布式系统中重要的组件,目前使用较多的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ。

消息队列主要解决了应用耦合、异步处理、流量削锋等问题。

二、Rabbit特点


RabbitMQ 是一款使用Erlang语言开发的,实现AMQP(高级消息队列协议)的开源消息中间件,它实现了高效、可靠、可扩展的消息传递机制。以下是 RabbitMQ 的一些主要特点:

  • 可靠性:RabbitMQ 提供了消息持久化、确认机制、事务等功能,确保消息传递的可靠性。
  • 灵活性:RabbitMQ 支持多种消息传递模式,例如点对点、发布/订阅、通配符等,可以根据不同的应用场景选择合适的模式。
  • 可扩展性:RabbitMQ 支持集群部署,可以通过添加节点来扩展消息处理能力。
  • 与多种编程语言兼容:RabbitMQ 提供了多种客户端库,可以与多种编程语言进行集成,例如 Java、Python、Go 等。
  • 丰富的功能:RabbitMQ 提供了多种功能,例如消息优先级、消息 TTL、延迟队列等,可以满足不同的业务需求。
  • 可视化管理界面:RabbitMQ 提供了一个可视化的管理界面,可以方便地管理队列、交换机、绑定关系等。

三、RabbitMQ的组成部分

  • Broker:消息队列服务进程。此进程包括两个部分:Exchange和Queue。
  • Exchange:消息队列交换机。按一定的规则将消息路由转发到某个队列
  • Queue:消息队列,存储消息的队列。
  • Producer:消息生产者。生产方客户端将消息同交换机路由发送到队列中。
  • Consumer:消息消费者。消费队列中存储的消息。

在这里插入图片描述

如图所示,RabbitMQ的工作流程分为以下几个部分

  • 消息生产者连接到RabbitMQ Broker,创建connection,开启channel。
  • 生产者声明交换机类型、名称、是否持久化等。
  • 生产者发送消息,并指定消息是否持久化等属性和routing key。
  • exchange收到消息之后,根据routing key路由到跟当前交换机绑定的相匹配的队列里面。
  • 消费者监听接收到消息之后开始业务处理。

四、RabbitMQ中Exchange


在RabbitMQ中,消息发送方不是直接将消息发送到queue中,而是先发送给exchange,由exchange再发送给对应的队列。exchange的类型有:**direct, topic, headers , fanout 。**默认的exchange,名为"",是一个没有名字的direct类型的exchange。发送到它的消息是基于路由键(routing key)路由到队列的。

4.1 Direct

direct,需要将一个队列绑定到交换机上,要求该消息与一个特定的routing key完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求routing key为 “green”,则只有routing key为“green”的消息才被转发,不会转发routing key为"red",只会转发routing key为"green”

4.2 Topic

可以理解为通配符匹配,将routing key和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配0个或多个词,符号“*”只能匹配一个词。

在这里插入图片描述

4.3 Fanout

Fanout 不需要指定routing key。你只需要简单的将队列绑定到交换机上。一个发送到该类型交换机的消息都会被广播到与该交换机绑定的所有队列上。
在这里插入图片描述

1.rabbitMQ的消息持久化的做法不是每接受一条消息就立即调用fsync,而是对接收到的消息进行缓存,接着再批量进行持久化。

3.rabbitMQ中的**AnonymousQueue** 默认是非持久化、自动删除的队列。

当消费者连接断开时,AnonymousQueue会被自动删除,队列中的消息也会被删除,不会持久化。

4.4 Headers

不处理routing key,而是根据发送的消息内容中的headers属性进行匹配。在绑定Queue与Exchange时指定一组键值对;当消息发送到RabbitMQ时会取到该消息的headers与Exchange绑定时指定的键值对进行匹配;如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers属性是一个键值对,可以是Hashtable,键值对的值可以是任何类型。而fanout,direct,topic 的路由键都需要要字符串形式的

在这里插入图片描述

RabbitMQ入门实战

首先在application.yml中配置RabbitMQ信息

spring:rabbitmq:host: 127.0.0.1port: 5672username: guestpassword: guest

接着添加配置类,在配置类中实现相关bean的注入

@Configuration
public class DirectRabbitConfig {@Beanpublic Queue rabbitmqDemoDirectQueue() {return new AnonymousQueue();/***   等价于  return new Queue("direct_demo",false,false,false);* 1、name:    队列名称* 2、durable: 是否持久化* 3、exclusive: 是否独享、排外的。如果设置为true,定义为排他队列。则只有创建者可以使用此队列。也就是private私有的。* 4、autoDelete: 是否自动删除。也就是临时队列。当最后一个消费者断开连接后,会自动删除。* */}@Beanpublic DirectExchange rabbitmqDemoDirectExchange() {//Direct交换机return new DirectExchange("demo_exchange", true, false);}@Beanpublic Binding bindDirect() {//链式写法,将队列和交换机进行绑定,并设置匹配键return BindingBuilder//绑定队列.bind(rabbitmqDemoDirectQueue())//到交换机.to(rabbitmqDemoDirectExchange())//并设置匹配键.with("demo");}@Beanpublic Sender sender() {//生产者类return new Sender();}@Beanpublic Receiver receiver() {//消费者类return new Receiver();}
}

接下来,创建发送消息的Sender类和消费消息的Receiver类

/*** 生产者类*/
public class Sender {@Autowiredprivate RabbitTemplate template;@Autowiredprivate DirectExchange direct;private final String MESSAGE = "Hello world";private final String key = "demo";@Scheduled(fixedDelay = 1000, initialDelay = 500)public void send() {template.convertAndSend(direct.getName(), key, MESSAGE);System.out.println("sending message: " + MESSAGE);}}
/*** 消费者类*/
@RabbitListener(queues = "#{rabbitmqDemoDirectQueue.name}")
public class Receiver {@RabbitHandlerpublic void receive(String msg) {System.out.println("receive message: " + msg);}
}

最后,创建启动类,并加上@EnableScheduling 注解

@SpringBootApplication
@EnableScheduling
public class RabbitDemoApplication {public static void main(String[] args) {SpringApplication.run(RabbitAmqpTutorialsApplication.class, args);}
}

打开http://localhost:15672,可以看到RabbitMQ消息发送情况等信息

在这里插入图片描述

五、RabbitMQ的一些机制

5.1 消息应答

一般情况下,RabbitMQ中的broker向消费者发送一条消息后,便立即将该消息标记为删除。由于消费者处理一个消息可能需要一段时间,假如在处理消息中途消费者挂掉了,我们会丢失其正在处理的消息以及后续发送给该消费这的消息。为了保证消费者消费的可靠性,RabbitMQ 引入消息应答机制,即:**消费者在接收消息并且处理完该消息之后,才告知 RabbitMQ 可以把该消息删除了。**RabbitMQ 中消息应答方式有两种:自动应答(默认)、手动应答。

  • 自动应答

自动应答是RabbitMQ默认采用的消息应答方式,是指broker不在乎消费者对消息处理是否成功,都会告诉队列删除消息。如果处理消息失败,又没有捕获异常,则会实现自动补偿(队列重新向消费者投递消息);如果捕获异常了,broker以为消息消费成功,就会将消息从队列中删除,导致数据丢失。

  • 手动应答

手动应答,是指消费者处理完业务逻辑之后,手动返回ack(通知)告诉broker消息处理完了,你可以删除消息了;或者手动返回nack消息,告诉broker消息处理失败,别删除消息。如果消费者挂了而没有发送ACK或NACK,那么RabbitMQ会认为该消息未被处理,会将该消息重新分发给其他消费者,直到有一个消费者成功处理并发送ACK或NACK为止。这个过程被称为消息的重新入队列。在重新入队列的过程中,RabbitMQ会在消息的属性中增加一个计数器,表示该消息被重新分发的次数。如果该计数器的值超过了一个预定的阈值,那么RabbitMQ可能会将该消息标记为“死信”,并将其发送到一个指定的死信交换机(dead letter exchange)中。这个机制可以避免消息在系统中无限制地被重新分发,从而引起系统性能问题。

在springboot的application.yml中可以设置RabbitMQ的应答机制

spring:rabbitmq:listener:simple:acknowledge-mode: manual

消费者

@RabbitListener(queues = "#{Queue1.name}")public void onMessage1(Message message, Channel channel) throws Exception {try {MessageProperties messageProperties = message.getMessageProperties();byte[] body = message.getBody();String content = new String(body, 0, body.length, messageProperties.getContentEncoding());System.out.println("receiver1: " + content);channel.basicAck(messageProperties.getDeliveryTag(), true);} catch (Exception e) {channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);}}

5.2 持久化

默认情况下 RabbitMQ 退出或由于某种原因崩溃时,它会清空队列和消息,除非告知它不要这样做。确保消息不会丢失需要做两件事:我们需要将队列和消息都标记为持久化

  • 队列持久化

  • 在这里插入图片描述

  • 消息持久化(在Spring Boot中使用RabbitTemplate发送消息时,默认情况下消息是持久化的)

@Autowired
private RabbitTemplate rabbitTemplate;public void sendMessage(String message) {MessageProperties properties = new MessageProperties();properties.setDeliveryMode(MessageDeliveryMode.PERSISTENT); // 设置消息的持久化属性Message rabbitMessage = new Message(message.getBytes(), properties);rabbitTemplate.convertAndSend("exchangeName", "routingKey", rabbitMessage);
}

5.3 不公平分发

RabbitMQ 默认分发消息采用的轮询分发模式,但是在某种场景下这种策略并不是很好,比方说有两个消费者在处理任务,其中 consumer01 处理任务的速度非常快,而 consumer02 处理速度却很慢,此时如果我们还是采用轮询分发,就会使处理速度快的 consumer01 很大一部分时间处于空闲状态,而 consumer02 一直在干活。

可以通过设置channel的prefetchCount 为1,来实现不公平分发。该参数表示,该消费者当前只能处理一个消息。

channel.basicQos(1);

或者application.yml中设置

spring.rabbitmq.listener.simple.acknowledge-mode=manual      
spring.rabbitmq.listener.simple.prefetch=1

5.4 预取值

该值定义channel上允许的未确认消息的最大数量。一旦数量达到配置的数量,RabbitMQ 将停止在channel上传递更多消息,除非至少有一个未处理的消息被确认。假设在channel上有未确认的消息 5、6、7,8,并且channel的预取计数设置为 4,此时 RabbitMQ 将不会在该channel上再传递任何消息,除非至少有一个未应答的消息被 ack。比方说 tag=6 的消息刚刚被确认 ACK,RabbitMQ 将会感知这个情况到并再发送一条消息。对于自动确认机制,其预取值可以看做是无限。

5.5 发布确认

生产者将channel设置成 confirm 模式,一旦channel进入 confirm 模式,所有在该channel上面发布的消息都将会被指派一个唯一的 ID(从 1 开始),一旦消息被投递到所有匹配的队列之后,broker 就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了。

confirm 模式最大的好处在于他是异步的,一旦发布一条消息,生产者应用程序就可以在等channel返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果 RabbitMQ 因为自身内部错误导致消息丢失,就会发送一条 nack 消息,生产者应用程序同样可以在回调方法中处理该 nack 消息。

发布确认机制有三种策略:单个确认发布批量确认发布异步确认发布

  • 单个确认发布

是一种同步确认发布的方式,也就是发布一个消息之后只有它被确认发布,后续的消息才能继续发布

  • 批量确认发布

与单个等待确认消息相比,先发布一批消息然后一起确认可以极大地提高吞吐量,当然这种方式的缺点就是:当发生故障导致发布出现问题时,不知道是哪个消息出现问题了,我们必须将整个批处理保存在内存中,以记录重要的信息而后重新发布消息。当然这种方案仍然是同步的,也一样阻塞消息的发布。

  • 异步确认发布

异步确认虽然编程逻辑比上两个要复杂,但是性价比最高,无论是可靠性还是效率都没得说,他是利用回调函数来达到消息可靠性传递的,这个中间件也是通过函数回调来保证是否投递成功,

要开启发布确认,需要配置application.yml

spring:#项目名称application:name: rabbitmq-provider#配置rabbitMq 服务器rabbitmq:host: 127.0.0.1port: 5672username: rabbitMQpassword: rabbitMQ#确认消息已发送到交换机(Exchange)
#    publisher-confirm-type: SIMPLEpublisher-confirm-type: CORRELATED#确认消息已发送到队列(Queue)publisher-returns: true

然后,在rabbitTemplate中进行设置

@Slf4j
@Configuration
public class RabbitConfig {@Beanpublic RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory){RabbitTemplate rabbitTemplate = new RabbitTemplate();rabbitTemplate.setConnectionFactory(connectionFactory);// Mandatory为true时,消息通过交换器无法匹配到队列会返回给生产者,为false时匹配不到会直接被丢弃rabbitTemplate.setMandatory(true);rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {/***  ConfirmCallback机制只确认消息是否到达exchange(交换器),不保证消息可以路由到正确的queue;*  需要设置:publisher-confirm-type: CORRELATED;*  springboot版本较低 参数设置改成:publisher-confirms: true**  以实现方法confirm中ack属性为标准,true到达*  config : 需要开启rabbitmq得ack publisher-confirm-type*/@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {log.info("ConfirmCallback  确认结果 (true代表发送成功) : {}  消息唯一标识 : {} 失败原因 :{}",ack,correlationData,cause);}});rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {/***  ReturnsCallback 消息机制用于处理一个不可路由的消息。在某些情况下,如果我们在发送消息的时候,当前的 exchange 不存在或者指定路由 key 路由不到,这个时候我们需要监听这种不可达的消息*   就需要这种return机制**  config : 需要开启rabbitmq发送失败回退; publisher-returns 或rabbitTemplate.setMandatory(true); 设置为true*/@Overridepublic void returnedMessage(ReturnedMessage returned) {
//                实现接口ReturnCallback,重写 returnedMessage() 方法,
//                方法有五个参数
//                message(消息体)、
//                replyCode(响应code)、
//                replyText(响应内容)、
//                exchange(交换机)、
//                routingKey(队列)。log.info("ReturnsCallback    returned : {}",returned);}});return rabbitTemplate;}}

5.6 死信队列

死信就是无法被消费的消息。一般来说,producer 将消息投递到 broker 或者直接到 queue 中,consumer 从 queue 取出消息进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。

死信产生的原因:

  • 消息 TTL 过期
  • 队列达到最大长度(队列满了无法再添加数据到 mq 中)
  • 消息被拒绝(basic.reject 或 basic.nack)并且 requeue=false

5.7 延迟队列

延时队列,队列内部是有序的,最重要的特性就体现在它的延时属性上,延时队列中的元素是希望在指定时间到了以后或之前取出和处理,简单来说,延时队列就是用来存放需要在指定时间被处理的元素的队列。

RabbitMQ 中的 TTL

TTL 是 RabbitMQ 中一个消息或者队列的属性,表明一条消息或者该队列中的所有消息的最大存活时间,单位是毫秒。一条消息如果在TTL 设置的时间内没有被消费,则会成为"死信"。如果同时配置了队列的TTL 和消息的TTL,那么较小的那个值将会被使用。

实现延迟队列的两种方式:

  • 通过设置队列TTL+死信实现消息延迟

代码架构图如下所示,其中有两个direct类型的交换机XY,其中Y为死信交换机;还有三个队列QAQBQD,QA和QB为普通队列,其中QA中消息的ttl为10s,QB中消息的ttl为40s,QD为死信队列。队列与交换机之间的routing-key如图中连线上标注所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bbRRw2rv-1691716049857)(RabbitMQ%2079b5ad38df29400fa52ef0085a14b02f/Untitled%208.png)]

  • 通过设置消息TTL+死信实现消息延迟

以上延时队列的实现目前只有 10S 和 40S 两个时间选项,如果需要一个小时后处理,那么就需要增加TTL为一个小时的队列,如果是预定会议室然后提前通知这样的场景,岂不是要增加无数个队列才能满足需求?

因此我们需要做出一些优化,在这里新增了一个队列 QC,绑定关系如下,该队列不设置 TTL 时间,我们通过指定消息的 TTL 来实现消息的延迟

在这里插入图片描述

  • 下载延迟队列插件

参见:https://blog.csdn.net/qq_45173404/article/details/121687489

5.9 幂等性

所谓幂等性就是指用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。比如用户购买商品后支付后已经扣款成功,但是返回结果时出现网络异常,用户并不知道自己已经付费成功,于是再次点击按钮,此时就进行了第二次扣款,这次的返回结果成功。但是扣了两次用户的钱,这就出现了不满足幂等性,即用户对统一操作发起了一次或多次请求

对应消息队列 MQ 中出现的幂等性问题就是消息重复消费。比如消费者在消费 MQ 中的消息时,MQ 已把消息发送给消费者,消费者在给 MQ 返回 ack 时网络中断,故 MQ 未收到确认信息,该条消息会重新发给其他的消费者,或者在网络重连后再次发送给该消费者,但实际上该消费者已成功消费了该条消息,造成消费者的重复消费。

幂等性解决方案:https://zhuanlan.zhihu.com/p/176944177

5.10 优先级队列

在RabbitMQ中,队列需要设置为优先级队列的同时消息也必须设置消息的优先级才能生效,而且消费者需要等待消息全部发送到队列中才去消费因为这样才有机会对消息进行排序。

代码实现队列优先级

在这里插入图片描述

5.11 惰性队列

当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。之后发送的消息就会成为死信,可能会被丢弃,这就是消息堆积问题。

从RabbitMQ的3.6.0版本开始,就增加了Lazy Queues的概念,也就是惰性队列。惰性队列的特征如下:

  • 接收到消息后直接存入磁盘而非内存
  • 消费者要消费消息时才会从磁盘中读取并加载到内存
  • 支持数百万条的消息存储

代码实现惰性队列
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【雕爷学编程】Arduino动手做(202)---热释电效应、热释电元件与HC-SR505运动传感器模块

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&#x…

谈谈Spring与字节码生成技术

Java程序员几乎都了解Spring。 它的IoC(依赖反转)和AOP(面向切面编程)功能非常强大、易用。而它背后的字节码生成技术(在运行时,根据需要修改和生成Java字节码的技术)就是一项重要的支撑技术。 …

PK Nounique CASCADE DROP INDEX keep index

Explicit Control Over Indexes when Creating, Disabling, or Dropping PK/Unique Constraints (Doc ID 139666.1)​编辑To Bottom PURPOSEIn Oracle 9i, the DBA has an explicit control over how indexes are affectedwhile creating, disabling, or dropping Primary Ke…

自动切换HTTP爬虫ip助力Python数据采集

在Python的爬虫世界里,你是否也被网站的IP封锁问题困扰过?别担心,我来教你一个终极方案,让你的爬虫自动切换爬虫ip,轻松应对各种封锁和限制!快来跟我学,让你的Python爬虫如虎添翼! 首…

SpringBoot 项目使用 Redis 对用户 IP 进行接口限流

一、思路 使用接口限流的主要目的在于提高系统的稳定性,防止接口被恶意打击(短时间内大量请求)。 比如要求某接口在1分钟内请求次数不超过1000次,那么应该如何设计代码呢? 下面讲两种思路,如果想看代码可…

【redis 3.2 集群】

目录 一、Redis主从复制 1.概念 2.作用 2.1 数据冗余 2.2 故障恢复 2.3 负载均衡 2.4 高可用 3.缺点 4.流程 4.1 第一步 4.2 第二步 4.3 第三步 4.4 第四步 5.搭建 5.1 主 5.2 从 6.验证 二、Reids哨兵模式 1.概念 2.作用 2.1 监控 2.2 自动故障转移 2.…

ArcGIS Pro基础:【按顺序编号】工具实现属性字段的编号自动赋值

本次介绍一个字段的自动排序编号赋值工具,基于arcgis 的字段计算器工具也可以实现类似功能,但是需要自己写一段代码实现, 相对而言不是很方便。 如下所示,该工具就是【编辑】下的【属性】下的【按顺序编号】工具。 其操作方法是…

redis基础

目录 前言 一、概述 1.NoSQL 2.Redis 二、安装 1.编译安装 2.RPM安装 三、目录结构 四、命令解析 五、redis登录更改 六、数据库操作 (一)、登录数据库 1.本地 2.远程登录 (二)、数据操作 1.数据库操作 2.数据操作 …

C++笔记之将定时器加入向量并设置定时器的ID为i

C笔记之将定时器加入向量并设置定时器的ID为i code review! 文章目录 C笔记之将定时器加入向量并设置定时器的ID为i关于代码中的void operator()() 运行 代码 #include <chrono> #include <iostream> #include <thread> #include <vector>// 定义定时…

京东秋招攻略,备考在线测评和网申笔试

京东秋招简介 伴随着社会竞争越来越激烈&#xff0c;人们投递简历的岗位也变得越来越多元&#xff0c;而无论人们的选择面变成何样&#xff0c;那些知名度较高的企业&#xff0c;永远都备受关注&#xff0c;只要其一发布招聘公告&#xff0c;总有人第一时间踊跃报名。而作为这…

linux自启动程序

嵌入式linux下有软件需要自启动&#xff0c;只需要在/etc/init.d/rcS末尾添加所要启动的程序即可&#xff0c;开机就会自动运行 vi /etc/init.d/rcS在文件末尾添加 例&#xff1a;

Zabbix6 对接飞书告警

文章目录 Zabbix对接飞书告警背景创建飞书群组Zabbix配置创建告警媒介类型创建动作用户关联飞书告警 Zabbix对接飞书告警 背景 运维 你看下他的进程是不是挂了&#xff0c;之前在9点28分有发消息的&#xff0c;这次没有发消息 哐哐哐的去看了一通&#xff0c;确实有个进程之前…

Nginx的优化和防盗链

一、Nginx的优化 1、隐藏版本号 curl -I http://192.168.79.28 #查看信息&#xff08;版本号等&#xff09;方法一&#xff1a;修改配置文件 vim /usr/local/nginx/conf/nginx.conf vim /usr/local/nginx/conf/nginx.conf http {include mime.types;default_type ap…

【Grafana】中文界面配置 v10.0.3

比如通过 docker run -d -p 3000:3000 -v /e/code/monitor/grafana/grafana.ini.txt:/etc/grafana/grafana.ini grafana/grafana运行一个容器&#xff08;最新是v10.0.3&#xff09;。 在 /admin/settings 可以看到 users 部分有一个 default_language 配置。 所以在挂载到 …

在vue项目使用数据可视化 echarts ,柱状图、折线图、饼状图使用示例详解及属性详解

官网地址&#xff1a;Apache ECharts ​一、下载插件并在页面中引入 npm install echarts --save 页面导入&#xff1a; import * as echarts from echarts 全局导入&#xff1a; main.js 中&#xff0c;导入并注册到全局 import echarts from echarts Vue.prototype.$echart…

【算法】双指针——leetcode盛最多水的容器、剑指Offer57和为s的两个数字

盛水最多的容器 &#xff08;1&#xff09;暴力解法 算法思路&#xff1a;我们枚举出所有的容器大小&#xff0c;取最大值即可。 容器容积的计算方式&#xff1a; 设两指针 i , j &#xff0c;分别指向水槽板的最左端以及最右端&#xff0c;此时容器的宽度为 j - i 。由于容器…

2、简单上手+el挂载点+v-xx(v-text、v-html、v-on、v-show、v-if、v-bind、v-for)

官网&#xff1a; vue3&#xff1a;https://cn.vuejs.org/ vue2&#xff1a;https://v2.cn.vuejs.org/v2/guide/ 简单上手&#xff1a; 流程&#xff1a; 导入开发版本的Vue.js <!--开发环境版本&#xff0c;包含了有帮助的命令行警告--> <script src"https…

SD-MTSP:光谱优化算法LSO求解单仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、光谱优化算法LSO 光谱优化算法&#xff08;Light Spectrum Optimizer&#xff0c;LSO&#xff09;由Mohamed Abdel-Basset等人于2022年提出。 参考文献&#xff1a; [1]Abdel-Basset M, Mohamed R, Sallam KM, Chakrabortty RK. Light Spectrum Optimizer: A Novel Physi…

React Native 样式布局基础知识

通过此篇笔记能够学习到如下的几个知识点 在 React Native 中使用样式的一些细节了解 React Native 的 Flex 布局概念了解 React Native 的 flex 布局属性React Native 如何添加多样式属性React Native 中绝对布局和相对布局 React Native 中的 Flex 布局概念 1、主轴和交叉…

JVM运行时五大数据区域详解

前言&#xff1a; java虚拟机再执行Java程序的时候把它所拥有的内存区域划分了若干个数据区域。这些区域有着不同的功能&#xff0c;各司其职。这些区域不但功能不同&#xff0c;创建、销毁时间也不同。有些区域为线程私有&#xff0c;如&#xff1a;每个线程都有自己的程序计数…