RabbitMQ 笔记一

概览

MQ基本概念

RabbitMQ入门

基本工作模

1.MQ是什么?

MQ:Message Queue, 存储消息的中间件,是消息发送过程中的暂存容器,主要用于解决分布式系统进程间的通信。

分布式系统通信的两种方式:直接远程调用、借助第三方间接通信

为什么要使用消息中间件?

如有一个电商交易的场景,用户下单之后调用库存系统减库存,然后调用物流系统进行发货,如果刚开始交易,库存,物流都是属于一个系统,那么他们之间就是接口调用。但是随着系统的发展,各个模块业务越来越庞大、业务逻辑越来越复杂,这个时候就必然要做服务化和业务拆分。这个时候就需要考虑这些系统之间是如何交互的。首先想到的就是RPC(Remote Procedure Call),但是随着系统的发展,可能一笔交易后序需要调用几十个接口位于不同系统的接口,比如短信服务、邮件服务等等,这个时候就需要消息中间件来解决问题了。消息中间件最突出的特点就是提供数据传输的可靠性和高效性,主要解决分布式的系统数据传输需求

摘自:为什么使用消息中间件_为什么用消息中间件-CSDN博客

使用MQ的优势:

(1)应用解耦:提高系统容错性和可维护性

        整个系统耦合,会导致系统容错性低、可扩展性低、可维护性低。解耦之后,一个系统挂了,其它系统不会有问题。容错性高、可扩展性高、可维护性高。

(2)异步提速:提升用户体验和系统吞吐量.

        如果一个订单系统同步执行:则有: 订单进数据库20ms+调用子系统一300ms+调用子系统二300ms+调用子系统三300ms=920ms,用户等待920ms

        如果采用异步模式:则有 订单进数据库20ms+消息发到MQ5ms=25ms,用户等待25ms

(3)削峰填谷:提高系统稳定性

        请求瞬间增多每秒5000个,但是子系统每秒只能处理1000请求。

        削峰指的是:提高子系统的稳定性。加入中间件后,所有请求进入消息队列。帮子系统处理高并发的请求量。

        填谷指的是:大量的消息积压在MQ里。子系统每秒从MQ拉取1000个进行处理,直到处理完所有积压的消息。

使用MQ的劣势

(1)系统可用性降低

        引入的第三方插件|依赖越多,系统稳定性越差。

        如果MQ宕机,业务功能就会收到影响。需要额外的工作来确保MQ高可用性。

(2)系统复杂性提高

        没有MQ时:系统间同步远程调用

        引入MQ时:通过MQ异步调用

        引发的问题:如何保证消息不被重复消费?如何处理消息丢失?如何保证消息传递的顺序性。

(3)一致性问题

        消息:A——>MQ——>B|C|D

        如果BC处理成功,D失败了,如何保证数据一致性。

使用MQ应满足什么条件?

  1. 生产者不需要消费者的反馈。(消费者消费消息后返回值为空,这才能使异步调用成为可能)
  2. 容许短暂的不一致
  3. 用了有效果:解耦、提速、削峰等,超过引入MQ的管理成本

常见的MQ产品

2.RabbitMQ概述

RabbitMQ简介:

2007年,Rabbit技术公司 基于AMQP标准开发 Rabbit MQ1.0

使用Erlang语言(一种专门为高并发、分布式系统开发的语言|电信领域使用广泛)

AMQP协议

  1. Advanced Message Queuing Protocol高级消息队列协议
  2. 网络协议,应用层协议的一个开放标准,为面向消息的中间件设计。
  3. 2006年,AMQP规范发布(类比HTTP)
  4. 基于此协议的客户端与消息中间件之间传递消息,不受客户端/中间件产品、开发语言等限制。

RabbitMQ的组成:

Broker中间件,用于接收发信息的用用,如:RabbitMQ Server
Virtual host

虚拟机,处于多租户和安全因素设计的,把AMQP基本组件划分到一个虚拟的分组中,类似于网络中的namespace 。

应用场景:用户隔离

        多个不同用户使用同一个RabbitMQ时,可以划分出多个vhost,每个用户在自己的vhost创建exchange/queue等。

Connection链接,publisher/consumer和broker之间建立TCP链接。
Channel

connection内部的逻辑链接。作为一个轻量级Connection,极大减少了操作系统建立TCP链接的开销。

存在原因:        

        如果每次访问MQ都建立链接,消息量大的时候建立TCP链接,开销非常大,效率也低。

        所以使用channel内部逻辑链接,如果应用支持多线程,通常每个thread独占一个channel通信。

AMQP method中

        包含channel id帮助客户端和message broker识别channel

        所以channel之间是完全隔离的

Exchange

交换机,message到达broker的第一站,根据分发规则,匹配查询表中的routing key, 分发消息到queue。

常见的类型

        direct:        point to point

        topic:         publisher-subscribe

        fanout:       multicast

Queue消息队列,消息最终被送到这里等待被消费。
Binding

绑定,exchange 和 queue之间的虚拟连接,binding中包含routing key.

Binding信息被保存在exchange的查询表中,是message分发的依据。

RabbitMQ的工作模式:

        6种,包含:简单模式、work queues、Publish/Subscribe 发布与订阅模式、Routing 路由模式、Topics主题模式、RPC远程调用模式。

RabbitMQ官网:RabbitMQ Tutorials — RabbitMQ

补充:

        JMS:java消息服务(Java Message Service)应用程序接口,是java平台关于面向消息的中间件API

        JMS是Java EE 规范的一种,类比JDBC.

        很多消息中间件都实现了JMS规范,如:ActiveMQ。RabbitMQ没有提供JMS的实现,但开源社区有。

3.RabbitMQ的简单实现

RabbitMQ的安装:

1.安装RabbitMQ软件:

windows环境下安装RabbitMQ(超详细)_windows安装rabbitmq-CSDN博客

java依赖:

<dependency>
  <groupId>com.rabbitmq</groupId>
  <artifactId>amqp-client</artifactId>
  <version>5.20.0</version>
</dependency>

2.开启管理界面及配置:

  • 默认端口号:5672
  • 图形化界面地址: http://127.0.0.1:15672
  • 登陆名: guest    密码:guest   
  • 配置文件:

3.启动服务及基础配置:

RabbitMQ简单模式:

RabbitMQ生产者:

package org.example.producer;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class SimpleProducer {
    public void publishMessage() throws IOException, TimeoutException {
        //1.创建连接工厂
        ConnectionFactory factory=new ConnectionFactory();
        //2.设置参数
        factory.setHost("127.0.0.1");//ip 默认值localhost
        factory.setPort(5672);//端口 默认值5672
        factory.setVirtualHost("/itcast");//虚拟机 默认值/
        factory.setUsername("heima");
        factory.setPassword("heima");
        //3.创建链接 Connection
        Connection connection=factory.newConnection();
        //4.创建Channel
        Channel channel=connection.createChannel();
        //5.创建队列Queue
        /*
        queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
         queue: 队列名称
         durable: 是否持久化,是的话,mq重启后,数据还在。
         exclusive:
            是否独占,只能有一个消费者监听队列
            当connection关闭时,是否删除队列
          autoDelete: 是否自动删除,当没有consumer时,自动删除。
          arguments: 参数
         */
        channel.queueDeclare("hello_world",true,false,false,null);
        //6.发送消息
        /*
        basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body) t
        exchange:交换机名称,简单模式下交换机会使用默认的“”
        routingKey: 路由名称
        props: 配置消息
        body:  发送消息数据
         */
        String body="hello rabbitMQ!";
        channel.basicPublish("","hello_world",null,body.getBytes());
        //7.释放资源
        channel.close();
        connection.close();
    }
}

生产者生产一个消息:

RabbitMQ消费者:

package org.example.consumer;



import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class SimpleConsumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        SimpleConsumer producer=new SimpleConsumer();
        producer.consumerMessage();
    }
    public void consumerMessage() throws IOException, TimeoutException {
        //1.创建连接工厂
        ConnectionFactory factory=new ConnectionFactory();
        //2.设置参数
        factory.setHost("127.0.0.1");//ip 默认值localhost
        factory.setPort(5672);//端口 默认值5672
        factory.setVirtualHost("/");//虚拟机 默认值/
        factory.setUsername("guest");
        factory.setPassword("guest");
        //3.创建链接 Connection
        Connection connection=factory.newConnection();
        //4.创建Channel
        Channel channel=connection.createChannel();
        //5.创建队列Queue
        /*
        queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
         queue: 队列名称
         durable: 是否持久化,是的话,mq重启后,数据还在。
         exclusive:
            是否独占,只能有一个消费者监听队列
            当connection关闭时,是否删除队列
          autoDelete: 是否自动删除,当没有consumer时,自动删除。
          arguments: 参数
         */
        channel.queueDeclare("hello_world",true,false,false,null);
        //6.接收消息
        /*
        basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body) t
        exchange:交换机名称,简单模式下交换机会使用默认的“”
        routingKey: 路由名称
        props: 配置消息
        body:  发送消息数据
         */
        Consumer consumer = new DefaultConsumer(channel){
            /*
            此处重写该方法是为了打印回调结果
            回调方法,收到回调方法后,会自动执行该方法
            consumerTag: 标识
            envelope: 获取一些信息,交换机,路由key
            properties: 配置信息
            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));
            }

        };
        channel.basicConsume("hello_world",true,consumer);
        //7.不需要释放资源,因为要监听队列

    }
}

总结:

P:生产者,也就是要发送消息的程序。

C:   消费者,消息的接收者,监听队列等待消息到来。

Queue: 消息队列,类似邮箱,可以缓存消息,生产者向其中投递消息,消费者从中取出消息。

4.5种基本工作模式

(1)简单模式 Hello World:

一个生产者,一个队列,一个消费者,不需要设置交换机(使用默认交换机)

(2)工作队列模式Work Queue:

特点: 一个生产者,一个队列,多个消费者(竞争关系),不需要设置交换机(使用默认交换机),同一个消息,对消费者来说是竞争关系,只有一个消费者能消费。

应用场景:对于任务过重或任务较多的情况使用工作队列可以提高任务处理速度。

例如:短信服务部署多个,只需要有一个节点发送成功即可。

发送端:发布多条消息

//创建新的队列
        channel.queueDeclare("work_queues",true,false,false,null); 
//发多条消息
        String body="hello rabbitMQ!";
        for(int i=0;i<10;i++){
            channel.basicPublish("","hello_world",null,(i+"-----"+body).getBytes());
        }

接收端:多个消费者竞争消费

创建两个消费者consumer1和consumer2,先启动两个消费者,再启动生产者生产消息,观察到两个消费者的消费过程。

消费者需要修改的地方:监听新的队列

channel.basicConsume("work_queues",true,consumer);

consumer1:

consumer2:

(3)发布Publish/subscribe:

        需要设置类型为fanout的交换机,并且交换机和队列进行绑定,当消息发送到交换机后,交换机将消息发送到绑定队列。

订阅模式多了一个交换机概念Exchange,且过程略有变化:

P: 消息生产者,消息发送给交换机

C:消息的接收者,监听消息队列,等待消息到来

Queue: 消息队列,接收消息,缓存消息。

Exchange: 交换机,只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失。

发送端:引入交换机,并对交换机和队列进行绑定

创建交换机、两个队列、绑定交换机和队列;发送消息并释放资源

其中交换机类型:BuiltinExchangeType枚举

关键代码

//4.创建Channel
        Channel channel=connection.createChannel();

        //定义交换机
        /*
        exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments) throws IOException {
        exchange: 交换机名称
        type: 交换机类型
            DIRECT("direct"),:定向
            FANOUT("fanout"),:扇形(广播),发送消息到每一个消费者
            TOPIC("topic"),:通配符的方式
            HEADERS("headers");:参数匹配

        durable: 是否持久化
        autoDelete: 自动删除
        internal: 内部使用,一般false
        arguments: 参数
         */
        String exchangeName="test_fanout";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);


        //5.创建队列Queue
        String queueName1="test_fanout_queue1";
        String queueName2="test_fanout_queue2";
        channel.queueDeclare(queueName1,true,false,false,null);
        channel.queueDeclare(queueName2,true,false,false,null);

        //绑定交换机
        /*
         queueBind(String queue, String exchange, String routingKey, Map<String, Object> arguments)
         queue:队列名称
         exchange:交换机名称
         routingKey:路由键,绑定规则
            如果交换机的类型为fanout,routingKey设置为“”
         arguments:参数
         */
        channel.queueBind(queueName1,exchangeName,"");
        channel.queueBind(queueName2,exchangeName,"");

        //6.发送消息
        String body="日志信息: 张三调用了FindAll方法...日志级别:info...";
        channel.basicPublish(exchangeName,"",null,body.getBytes());

        //7.释放资源
        channel.close();
        connection.close();

 接收端:创建两个消费者,分别监听两个队列

consumer1监听queue1,consumer2监听queue2

//Consumer1:
channel.basicConsume("test_fanout_queue1",true,consumer);

//Consumer2:
channel.basicConsume("test_fanout_queue2",true,consumer);

启动生产者,消息生产正常,启动消费者1,启动消费者2,两个消费者都收到了消息。

consumer1:

consumer2: 

(4)路由模式Routing:

        需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key, 当发送消息到交换机后,交换机会根据routing key 将消息发送到对应的队列。

队列与交换机的绑定,不能是任意绑定,而是根据routing key绑定队列,消息根据绑定来决定分发到哪个队列中。

发送端:交换机绑定队列时,指定路由模式

注意:交换者的类型为:BuiltinExchangeType.TOPIC

关键代码:

 //4.创建Channel
        Channel channel=connection.createChannel();
        String exchangeName="test_topic";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);


        //5.创建队列Queue
        String queueName1="test_routing_queue1";
        String queueName2="test_routing_queue2";
        channel.queueDeclare(queueName1,true,false,false,null);
        channel.queueDeclare(queueName2,true,false,false,null);

        //绑定交换机
        /*
         queueBind(String queue, String exchange, String routingKey, Map<String, Object> arguments)
         queue:队列名称
         exchange:交换机名称
         routingKey:路由键,绑定规则
            如果交换机的类型为fanout,routingKey设置为“”
         arguments:参数
         */
        channel.queueBind(queueName1,exchangeName,"error");
        channel.queueBind(queueName2,exchangeName,"info");
        channel.queueBind(queueName2,exchangeName,"error");
        channel.queueBind(queueName2,exchangeName,"warning");

        //6.发送消息
        String body="日志信息: 张三调用了FindAll方法...日志级别:info...";
        channel.basicPublish(exchangeName,"info",null,("info:\t"+body).getBytes());
        channel.basicPublish(exchangeName,"error",null,("error:\t"+body).getBytes());
        channel.basicPublish(exchangeName,"warning",null,("warning:\t"+body).getBytes());

接收端:创建Consumer1类,Consumer2类。

consumer1 监听队列1, consumer2监听队列2

//consumer1 
channel.basicConsume("test_routing_queue1",true,consumer);


//consumer2
channel.basicConsume("test_routing_queue2",true,consumer);

启动生产者生产正常,启动消费者1,启动消费者2

consumer1:

consumer2:

(5)通配符模式Topic:

        需要设置类型为topic的交换机,交换机和队列进行绑定,并且指定通配符方式的routing key, 当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列。

应用场景:如像根据日志级别监听某个子系统 系统名.error 消息,并入库

发送者

指定路由方式,但是路由方式以通配符匹配的形式存在:  #匹配一个  *匹配多个

 channel.queueBind(queueName1,exchangeName,"#.error");
        channel.queueBind(queueName2,exchangeName,"order.*");
        channel.queueBind(queueName2,exchangeName,"*.*");

        //6.发送消息
        String body="日志信息: 张三调用了FindAll方法...日志级别:info...";
        channel.basicPublish(exchangeName,"order.info",null,("order.info:\t"+body).getBytes());
        channel.basicPublish(exchangeName,"order.error",null,("order.error:\t"+body).getBytes());
        channel.basicPublish(exchangeName,"A.error",null,("A.error:\t"+body).getBytes());
      

接收端:创建Consumer1类,Consumer2类。

consumer1监听队列1,consumer2监听队列2

//Consumer1
channel.basicConsume("test_topic_queue1",true,consumer);


//Consumer2
channel.basicConsume("test_topic_queue2",true,consumer);

consumer1:

consumer2:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue---打印本地当前时间Demo

<template><view class"content" tap"getCurrentTime()">打印时间</view> </template><script>export default {data() {return {title: Hello}},onLoad() {},methods: {getCurrentTime() {//获取当前时间并打印var _this …

E7数据库备份和恢复

E7数据库备份和恢复 一、实验目的 在Mysql上&#xff0c;学习如何备份数据库和恢复的各种方法。 二、实验要求: 1、基本硬件配置:英特尔Pentium III 以上,大于4G内存&#xff1b; 2、软件要求:Mysql&#xff1b; 3、时间:1小时&#xff1b; 4、撰写实验报告并按时提交。 三、…

windows下git pull超时,ping不通github

报错 ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. 解决办法 修改hosts 最后加一行&#xff0c;文件位置&#xff1a;…

利用 “diart“ 和 OpenAI 的 Whisper 简化实时转录

利用 "diart" 和 OpenAI 的 Whisper 简化实时转录 工作原理 Diart 是一个基于人工智能的 Python 库&#xff0c;用于实时记录说话者语言&#xff08;即 "谁在什么时候说话"&#xff09;&#xff0c;它建立在 pyannote.audio 模型之上&#xff0c;专为实时…

Ubuntu 22.04安装Nginx负载均衡

君衍. 一、编译安装Nginx二、轮询算法实现负载均衡三、加权轮询算法实现负载均衡四、ip_hash实现负载均衡 一、编译安装Nginx 这里我们先将环境准备好&#xff0c;我使用的是Ubuntu22.04操作系统&#xff1a; 这个是我刚安装好的&#xff0c;所以首先我们进行保存快照防止安装…

金融OCR领域实习日志(二)——四种OCR模型效果测试(附图)

文章目录 四种模型ocr效果简单测试模型场景1.paddle框架下PP-OCRv31.1.效果如下&#xff1a;1.2.总结 2.paddle框架下ppocr_server_v22.1.效果如下2.2.总结 3.CnOCR3.1.效果如下3.2.总结 4.TesseractOCR4.1.效果如下4.2.总结 5.后续想法 四种模型ocr效果简单测试 模型 PP-OCR…

文件操作---C++

文件操作目录 1.文本文件1.1写文件1.2读文件1.2.1第一种方式&#xff1a;流输入方式1.2.2第二种方式&#xff1a;getline成员函数1.2.3第三种方式&#xff1a;getline全局函数1.2.4第四种方式&#xff1a;按一个一个字符读取 2.二进制文件2.1写文件2.2读文件 程序运行时产生的数…

【C++进阶】STL容器--list使用迭代器问题分析

目录 前言 1. list的基本使用 1.1 list构造函数 1.2 list迭代器 1.3 list capacity 1.4 list元素访问 1.5 list 修改操作 insert erase swap resize clear 2. list失效迭代器问题 3. list使用算法库函数问题 总结 前言 list&#xff08;链表&#xff09;在C中非常重要…

分享7种SQL的进阶用法

分享7种SQL的进阶用法 前言 还只会使用SQL进行简单的insert、update、detele吗&#xff1f;本文给大家带来7种SQL的进阶用法&#xff0c;让大家在平常工作中使用SQL简化复杂的代码逻辑。 1.自定义排序&#xff08;ORDER BY FIELD&#xff09; 在MySQL中ORDER BY排序除了可以…

vue模拟聊天页面列表:滚动到底部,滚动到顶部触发加载更多

先看下效果&#xff1a; 代码&#xff1a; <template><div><div style"text-align: center"><button click"scrollTop">滚动到顶部</button><button click"scrollBottom">滚动到底部</button></d…

GitHub Copilot 与 ChatGPT:哪种工具更适合软件开发?

GitHub Copilot 与 ChatGPT&#xff1a;哪种工具更适合软件开发&#xff1f; 比较 ChatGPT 与 GitHub Copilot编程语言功能性定制化训练数据上下文准确性 ChatGPT 与 GitHub Copilot&#xff1a;哪个更适合软件开发&#xff1f;常见问题解答&#xff1a; 不断发展的编程世界正在…

基数排序算法

1. 排序算法分类 十种常见排序算法可以分为两大类&#xff1a; 比较类排序&#xff1a; 通过比较来决定元素间的相对次序&#xff0c;由于其时间复杂度不能突破O(nlogn)&#xff0c;因此也称为非线性时间比较类排序。比较类排序算法包括&#xff1a;插入排序、希尔排序、选择…

matlab绘图杂谈-stem函数和plot函数

出发点 今天在论文中看到一副这样的图&#xff0c;它既有曲线&#xff0c;又有点&#xff0c;并且对两者都添加了图例。三条曲线应该是用plot函数绘制的&#xff0c;而target哪个绿色的圆圈&#xff0c;我的理解是用stem函数绘制的。它只是1个点&#xff0c;并且没有竖线&…

Ps:可选颜色

可选颜色 Selective Color命令可以按指定的颜色&#xff08;范围&#xff09;进行单独的调整&#xff0c;且不会影响图像中的其他颜色。 Ps菜单&#xff1a;图像/调整/可选颜色 Adjustments/Selective Color Ps菜单&#xff1a;图层/新建调整图层/可选颜色 New Adjustment Laye…

Qt 基于海康相机 的视频标绘

需求&#xff1a; 基于 视频 进行 标注&#xff0c;从而进行测量。 曾经搞在线教育时&#xff0c;尝试在视频上进行文字或者图形的绘制&#xff0c;但是发现利用Qt widget 传sdk 句柄的方式&#xff0c;只能使用窗口叠加的方式&#xff08;Qt 基于海康相机的视频绘图_海康相…

【WPF.NET开发】WPF 中的 Layout

本文内容 元素边界框布局系统测量和排列子元素面板元素和自定义布局行为布局性能注意事项子像素渲染和布局舍入 本主题介绍 Windows Presentation Foundation (WPF) 布局系统。 了解布局计算发生的方式和时间对于在 WPF 中创建用户界面非常重要。 1、元素边界框 在 WPF 中构…

React中使用LazyBuilder实现页面懒加载方法一

前言&#xff1a; 在一个表格中&#xff0c;需要展示100条数据&#xff0c;当每条数据里面需要承载的内容很多&#xff0c;需要渲染的元素也很多的时候&#xff0c;容易造成页面加载的速度很慢&#xff0c;不能给用户提供很好的体验时&#xff0c;懒加载是优化页面加载速度的方…

算法基础之树状数组

文章目录 树状数组 树状数组 树状数组能解决的最关键的问题就是能够 O ( log ⁡ n ) O(\log n) O(logn)内&#xff0c;给某个位置上的数&#xff0c;加上一个数&#xff0c;或者求前缀和 他和前缀和数组的区别就是&#xff0c;树状数组支持修改原数组的内容&#xff0c;而前缀…

前端学习之——react篇(渲染列表)

你将依赖 JavaScript 的特性&#xff0c;例如 for 循环 和 array 的 map() 函数 来渲染组件列表。 假设你有一个产品数组&#xff1a; const products [{ title: Cabbage, id: 1 },{ title: Garlic, id: 2 },{ title: Apple, id: 3 }, ]; 在你的组件中&#xff0c;使用 map…

视频尺寸魔方:分层遮掩3D扩散模型在视频尺寸延展的应用

▐ 摘要 视频延展(Video Outpainting)是对视频的边界进行扩展的任务。与图像延展不同&#xff0c;视频延展需要考虑到填充区域的时序一致性&#xff0c;这使得问题更具挑战性。在本文中&#xff0c;我们介绍了一个新颖的基于扩散模型的视频尺寸延展方法——分层遮掩3D扩散模型(…
最新文章