RabbitMQ系列(十一)RabbitMQ进阶-Queue队列详解-延时队列

2023-11-14

RabbitMQ进阶-Queue队列详解-延迟队列

1.延迟队列场景
1.1 场景

一般延迟队列用于特定事件发生后隔一段时间需要做特定处理的场景,下面举几个常见的栗子

1.电商系统中,若用户下单后30min不支付,自动取消订单
2.用户登录APP浏览特定商品20min后还没下单,自动推送商品评测信息的消息
3.调用第三方接口后,过30s去查询接口调用状态,比如简单的掉第三方接口发短信,掉完运营商不会立马告知你短信发送成功还是失败、所以设置30s后去主动查询下短信状态,然后更新此条短信状态(成功、失败、待回执)等

我们本篇文章,模拟场景 设置30s的延迟队列,消息在队列中延迟30s后,再去处理消息,实现业务逻辑

2.延迟队列实现方式

Rabbitmq本身是没有延迟队列的,要实现延迟消息,一般有两种方式:

  1. 通过Rabbitmq本身队列的特性TTL来实现,利用队列消息的存活时间来实现,设置队列的TTL消息存活周期 和死信交换机,延迟队列需要消息的存活时间TTL(Time To Live) 来丢弃消息,并使用Rabbitmq的死信交换机(Exchange)来负责消息的转发
  2. 在rabbitmq 3.5.7及以上的版本提供了一个插件(rabbitmq-delayed-message-exchange)来实现延迟队列功能。同时插件依赖Erlang/OPT18.0及以上
3.TTL+Exchange实现延迟队列

这种方式实现的原理就是利用队列消息存活时间TTL(Time To Live) ,超时就会丢弃本条消息,然后丢弃到死信交换机,死信交换机根据路由信息RoutingKey去负责路由转发,转发到相应的消费者来实现 延迟后业务逻辑处理
!!!注意我们设置TTL的队列是用做存储消息30s的,他并没有消费者
真正的消费者是绑定在死信交换机上面的,通过死信交换机设置的RoutingKey来路由到目标队列
实现原理:
在这里插入图片描述

3.1 初始化死信交换机

构造一个DeadLetterExchange 名字exchange_dead 和一个 target队列 名字 queue_delay_target,target队列就是接收死信消息,由他的消费者来处理延迟30s后的相关业务
交换机枚举类 ExchangeTypeEnum

package delay;

public enum ExchangeTypeEnum {

    DIRECT("exchange-direct-name", "direct"),
    FANOUT("exchange-fanout-name", "fanout"),
    TOPIC("exchange-topic-name", "topic"),
    HEADER("exchange-header-name", "headers"),
    UNKNOWN("unknown-exchange-name", "direct");

    /**
     * 交换机名字
     */
    private String name;
    /**
     * 交换机类型
     */
    private String type;

    ExchangeTypeEnum(String name, String type) {
        this.name = name;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public String getType() {
        return type;
    }

    public static ExchangeTypeEnum getEnum(String type) {
        ExchangeTypeEnum[] exchangeArrays = ExchangeTypeEnum.values();
        for (ExchangeTypeEnum exchange : exchangeArrays) {
            if (exchange.getName().equals(type)) {
                return exchange;
            }
        }
        return ExchangeTypeEnum.UNKNOWN;
    }

}

死信交换机、死信队列定义

package delay;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import conn.MqConnectUtil;

public class DelayDeadExchange {

    /**
     * 死信交换机
     */
    public static final String DEAD_EXCHANGE = "exchange_dead";
    /**
     * 目标队列,就是真正有消费者监听,要处理业务的队列
     */
    public static final String QUEUE_TARGET = "queue_delay_target";

    /**
     * 设置 rk=# 表示任意RK的消息过来,都可以路由到 dead_msg_quque这个队列
     */
    public static final String RK_QUEUE_TARGET = "rk.queue_delay_target";

    /**
     * 声明死信队列信息
     * <p>
     * 死信队列需要将 死亡的消息路由到 目标队列,从而使目标队列的消费者进行消费处理相关业务
     *
     * @throws Exception
     */
    public static void deadInit() throws Exception {
        // 获取到连接以及mq通道
        Connection connection = MqConnectUtil.getConnectionDefault();
        // 从连接中创建通道
        Channel channel = connection.createChannel();

        /*声明 直连交换机 交换机 String exchange,
         * 参数明细
         * 1、交换机名称
         * 2、交换机类型,topic
         */
        channel.exchangeDeclare(DEAD_EXCHANGE, ExchangeTypeEnum.DIRECT.getType());
        channel.queueDeclare(QUEUE_TARGET, true, false, false, null);

        /*交换机和队列绑定String queue, String exchange, String routingKey
         * 参数明细
         * 1、队列名称
         * 2、交换机名称
         * 3、路由key rk.queue_delay_target
         */
        channel.queueBind(QUEUE_TARGET, DEAD_EXCHANGE, RK_QUEUE_TARGET);

        //关闭通道和连接
        channel.close();
        connection.close();
    }

    public static void main(String[] args) throws Exception {
        deadInit();
    }
}

运行 deadInit(),初始化死信交换机及死信队列,查看下界面
在这里插入图片描述

3.2 生产者

生产者定义一个TTL队列 queue_delay_ttl 设置队列消息生命周期TTL:30s,路由RoutingKey :rk.ttl_queue_test 就是为了存放消息,让他超时死亡后,经过死信交换机路由转发
!!!注意该队列没有消费者,只有ttl参数及绑定的死信队列

package delay;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import conn.MqConnectUtil;
import subscrib3.ExchangeTypeEnum;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.Map;

import static delay.DelayDeadExchange.*;


public class DelayQueueProducer {
    /**
     * 延时队列名字
     */
    public final static String QUEUE_TTL = "queue_delay_ttl";
    /**
     * 设置延时队列的RK
     */
    public final static String RK_QUEUE_TTL = "rk.ttl_queue_test";


    /**
     * 生产 Direct直连 交换机的MQ消息
     */
    public static void produce() throws Exception {
        // 获取到连接以及mq通道
        Connection connection = MqConnectUtil.getConnectionDefault();
        // 从连接中创建通道
        Channel channel = connection.createChannel();

        /*声明 直连交换机 交换机 String exchange,
         * 参数明细
         * 1、交换机名称
         * 2、交换机类型,direct
         */
        channel.exchangeDeclare(ExchangeTypeEnum.DIRECT.getName(), ExchangeTypeEnum.DIRECT.getType());

        /* 声明(创建)队列  queueDeclare( String queue, boolean durable, boolean exclusive, boolean autoDelete,  Map<String, Object> arguments)
         * queue - 队列名
         * durable - 是否是持久化队列, 队列的声明默认是存放到内存中的,如果rabbitmq重启会丢失
         * exclusie - 是否排外的,仅限于当前队列使用
         * autoDelete - 是否自动删除队列,当最后一个消费者断开连接之后队列是否自动被删除,可以通过界面 查看某个队列的消费者数量,当consumers = 0时队列就会自动删除
         * arguments - 队列携带的参数 比如 ttl-生命周期,x-dead-letter 死信队列等等
         */
        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        // !!!!! 注意这里绑定的 RoutingKey 是 死信队列根据RK要路由到目标队列的RoutingKey,所以要用目标队列的RoutingKey
        arguments.put("x-dead-letter-routing-key", RK_QUEUE_TARGET);
        arguments.put("x-message-ttl", 30000);
        channel.queueDeclare(QUEUE_TTL, true, false, false, arguments);

        /*交换机和队列绑定String queue, String exchange, String routingKey
         * 参数明细
         * 1、队列名称
         * 2、交换机名称
         * 3、路由key rk.queue_delay_ttl
         */
        channel.queueBind(QUEUE_TTL, ExchangeTypeEnum.DIRECT.getName(), RK_QUEUE_TTL);


        /* 发送消息 String exchange, String routingKey, BasicProperties props, byte[] body
         * exchange - 交换机 ,"" 空时候指定的是 获取的virtualHost 虚拟服务器的 默认的exchang,每个virtualHost都有一个AMQP default type:direct 直接转发
         * queuename - 队列信息
         * props - 参数信息
         * message 消息体 byte[]类型
         */
        // 消息内容
        String message = "i=1" + " Hello World! Time:" + LocalDate.now() + " " + LocalTime.now();
        channel.basicPublish(ExchangeTypeEnum.DIRECT.getName(), RK_QUEUE_TTL, null, message.getBytes());
        System.out.println(" **** Producer  Sent Message: [" + message + "]");


        //关闭通道和连接
        channel.close();
        connection.close();
    }

    public static void main(String[] args) throws Exception {
//        //生产消息
        produce();
    }
}

运行produce() 生产1条消息,查看界面
在这里插入图片描述
TTL的队列中消息由1条,target中没有消息
在这里插入图片描述

3.3 消费者

30s后,生产者生产的消息,TTL生命周期到了,就死亡了,从DeadLetterExchange 路由到了Traget队列
在这里插入图片描述
看下Target队列,target队列中从 0 变成 了1条消息
在这里插入图片描述

消费者我们循环10次,让他等待消息,消费此消息

package delay;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
import conn.MqConnectUtil;

import static delay.DelayDeadExchange.*;


public class DelayTargetConsumer {

    public static void main(String[] argv) throws Exception {
        Connection connection = null;
        Channel channel = null;
        try {
            connection = MqConnectUtil.getConnectionDefault();
            channel = connection.createChannel();

            /*声明交换机 String exchange
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
            channel.exchangeDeclare(ExchangeTypeEnum.DIRECT.getName(), ExchangeTypeEnum.DIRECT.getType());

            /*声明队列
             * 参数明细:
             * 1、队列名称
             * 2、是否持久化
             * 3、是否独占此队列
             * 4、队列不用是否自动删除
             * 5、参数
             */
            channel.queueDeclare(QUEUE_TARGET, true, false, false, null);
            //交换机和队列绑定String queue, String exchange, String routingKey
            /**
             * 参数明细
             * 1、队列名称
             * 2、交换机名称
             * 3、路由key
             */
            channel.queueBind(QUEUE_TARGET, DEAD_EXCHANGE, RK_QUEUE_TARGET);


            System.out.println(" **** Consumer->1 Waiting for messages. To exit press CTRL+C");


            QueueingConsumer consumer = new QueueingConsumer(channel);

            /* 消息确认机制
             * autoAck true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
             * autoAck false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,如果消费者一直没有反馈,那么该消息将一直处于不可用状态
             *          并且服务器会认为该消费者已经挂掉,不会再给其发送消息,直到该消费者反馈
             *          !!!!!! 注意这里是 false,手动确认
             */
            channel.basicConsume(QUEUE_TARGET, false, consumer);

            int count = 0;
            while (count < 10) {
                QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println(" count:" + count + " **** Consumer->1 Received '" + message + "'");
                doSomeThing(message);
                //返回确认状态
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
                count++;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            channel.close();
            connection.close();
        }

    }


    /**
     * 模拟处理复杂逻辑:休眠100ms
     *
     * @param message
     * @throws Exception
     */
    public static void doSomeThing(String message) throws Exception {
        //遍历Count ,sleep , 接收一条消息后休眠 100 毫秒,模仿复杂逻辑
        Thread.sleep(100);
    }
}

运行consumer,接收到了此消息,队列清空
在这里插入图片描述
消费完毕,消息队列清零
在这里插入图片描述

4.安装插件实现延迟队列

RabbitMQ提供了插件,可以实现延迟队列,我们现在采用插件的方式来实现一下延迟队列

4.1 插件下载

去RabbitMQ的官网下载插件,插件地址:https://www.rabbitmq.com/community-plugins.html

找到 GitHub: rabbitmq/rabbitmq-delayed-message-exchange 的地方,下载
在这里插入图片描述

4.2 插件安装

把下载的 rabbitmq_delayed_message_exchange-3.8.0.ez 文件 复制到Rabbitmq安装路径 下面的 plugins/目录下
在这里插入图片描述

切换到Rabbitmq安装目录 sbin下,执行命令

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

在这里插入图片描述

打开界面Rabbitmq,新建交换机 plugin_delay_exchange,可以看到多了一种交换机 x-delay-message类型

在这里插入图片描述 多了一种交换机类型x-delay-message类型

4.3 延迟交换机插件使用

生产消息

package delay;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import conn.MqConnectUtil;

import java.util.HashMap;
import java.util.Map;

public class PluginsDelayExchange {

    /**
     * 延迟队列
     */
    public static final String PLUGIN_DELAY_QUEUE = "plugin_delay_queue";
    /**
     * 延迟队列RoutingKey
     */
    public static final String RK_PLUGIN_DELAY_QUEUE = "rk.plugin_delay_queue";

    /**
     * 延迟队列交换机
     */
    public static final String PLUGIN_DELAY_EXCHANGE = "plugin_delay_exchange";


    public static void main(String[] args) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = MqConnectUtil.getConnectionDefault();
        // 从连接中创建通道
        Channel channel = connection.createChannel();
        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-delayed-type", "direct");
        channel.exchangeDeclare(PLUGIN_DELAY_EXCHANGE, "x-delayed-message", true, false, arguments);
        channel.queueDeclare(PLUGIN_DELAY_QUEUE, true, false, false, null);
        channel.queueBind(PLUGIN_DELAY_QUEUE, PLUGIN_DELAY_EXCHANGE, RK_PLUGIN_DELAY_QUEUE);
        Map<String, Object> headers = new HashMap<>();
        //延迟10s后发送
        headers.put("x-delay", 10000);
        AMQP.BasicProperties props = new AMQP.BasicProperties.Builder().headers(headers).build();

        //延迟10s后 发送消息
        channel.basicPublish(PLUGIN_DELAY_EXCHANGE, RK_PLUGIN_DELAY_QUEUE, props, "该消息将在10s后发送到队列".getBytes());
        channel.close();
        connection.close();
    }
}

执行 produce,生产1条消息

4.4 查看结果

在这里插入图片描述
看下队列中的消息
在这里插入图片描述
所以说,插件的实现方式和死信队列的实现方式完全不同,一个是延迟发送、一个是延迟消费

  1. 插件看似立马发送,Produce进程已经结束了,过了10s后,队列才真正的有消息
  2. 死信队列TTL方式是立马发送,然后消息在队列中存活10sTTL时间,后被路由转发,由消费者消费

至此 死信队列讲完了


下一章 我们讲一下 RabbitMQ系列(十二)RabbitMQ进阶-消息确认机制之事务机制

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RabbitMQ系列(十一)RabbitMQ进阶-Queue队列详解-延时队列 的相关文章

  • 在 django 中使用 pika 的 Rabbitmq 监听器

    我有一个 django 应用程序 我想使用来自rabbit mq 的消息 我希望监听器在启动 django 服务器时开始使用 我正在使用 pika 库连接到rabbitmq 提供一些代码示例确实会有帮助 首先 您需要在 django 项目开
  • 如何禁用 RabbitMQ 默认 tcp 监听端口 - 5672

    我已经配置了RabbitMQrabbitmq config具有新端口号的文件 即带有 SSL 的 5671 现在我想禁用默认端口 即 5672 配置文件如下 rabbit ssl listeners 5671 ssl options cac
  • 我应该在 Django 项目中使用 Celery 还是 Carrot?

    我有点困惑我应该使用哪一个 我认为两者都可以 但其中一个比另一个更好或更合适吗 http github com ask carrot tree master http github com ask carrot tree master ht
  • 如何根据条件限制并发消息消耗

    场景 我已经简化了事情 许多最终用户可以从前端 Web 应用程序 生产者 开始工作 繁重的工作 例如渲染大型 PDF 这些作业被发送到单个持久的 RabbitMQ 队列 许多工作应用程序 消费者 处理这些作业并将结果写回到数据存储中 这个相
  • 保持鼠兔 BlockingConnection 存活而不禁用心跳

    我正在使用 pika 0 10 0 和 python 2 7 版本开发 RabbitMQ 消费者 在我的消费者客户端中 我有一个根据输入消息运行一段时间的进程 时间可能从 3 到 40 分钟不等 我不想禁用心跳 相反 我正在寻找一些回滚机制
  • 过期的消息不会从 RabbitMQ 中删除

    我通过生产者向 RabbitMQ 发送一条普通消息 然后发送第二条消息expiration属性分配给一个值 然后使用rabbitmqctl list queues命令我监视消息的状态 我发现如果我先发送一条普通消息 然后发送一条消息expi
  • Akka 的语言和产品替代品是什么?

    现在我正在看游戏框架 https www playframework com 并且非常喜欢它 Play 中提供的功能中最受宣传的部分之一是Akka http akka io 为了更好地理解 Akka 以及如何正确使用它 您能告诉我其他语言或
  • rabbitmq-erlang-client,使用 rebar 友好的 pkg,在开发环境上工作在 rebar 版本上失败

    我成功地将rabbitmq erlang client的rebar友好包用于一个简单的Hello World rebarized和OTP 兼容 应用程序 并且在开发环境中工作正常 我能够启动 erl 控制台并执行我的操作applicatio
  • 每次发布后我应该关闭通道/连接吗?

    我在 Node js 中使用 amqplib 但我不清楚代码中的最佳实践 基本上 我当前的代码调用amqp connect 当 Node 服务器启动时 然后为每个生产者和每个消费者使用不同的通道 而不会真正关闭它们中的任何一个 我想知道这是
  • 无法从 docker 将 RabbitMQ 连接到我的应用程序 [重复]

    这个问题在这里已经有答案了 我目前被这个问题困扰了大约一周 确实找不到合适的解决方案 问题是 当我尝试连接到 dockerized RabbitMQ 时 它每次都会给出相同的错误 wordofthedayapp wordofthedayap
  • RabbitMQ 中多个消费者如何订阅同一主题并获取同一消息

    首先 我知道类似问题已经有答案了here https stackoverflow com questions 10620976 rabbitmq amqp single queue multiple consumers for same m
  • 多个队列在一个通道中消耗

    我使用rabbitMq 来管理和使用队列 我有多个队列 它们的数量并不具体 我使用直接交换来发布消息 我怎样才能仅使用一个队列来消费每个队列的所有消息 基于routing key 渠道 此时我假设我有 5 个队列 我使用了 for 循环并为
  • springrabbitmq:无法将id设置为属性?

    我有一个属性文件 其中包含队列 其值为queue name 如果我在其他请使用该属性 那么它可以工作 但如果我在 id 上使用它 那么它会失败
  • 如何使用 Celery、RabbitMQ 和 Django 确保每个用户的任务执行顺序?

    我正在运行 Django Celery 和 RabbitMQ 我想要实现的是确保与一个用户相关的任务按顺序执行 具体来说 一次执行一个 我不希望每个用户执行任务并发 每当为用户添加新任务时 它应该取决于最近添加的任务 如果此类型的任务已为此
  • Celery 与rabbitmq 创建结果多个队列

    我已经用 RabbitMQ 安装了 Celery 问题是 对于返回的每个结果 Celery 都会在 Rabbit 中创建队列 并在交换 celeryresults 中使用任务 ID 我仍然想得到结果 但在一个队列上 我的芹菜配置 from
  • AMQP如何克服直接使用TCP的困难?

    AMQP如何克服直接使用TCP发送消息时的困难 或者更具体地说 在发布 订阅场景中 在 AMQP 中 有一个代理 该代理接收消息 然后完成将消息路由到交换器和队列的困难部分 您还可以设置持久队列 即使客户端断开连接 也可以为客户端保存消息
  • RabbitMQ 管理插件窗口呈现为空白页面

    I have installed Erlang RabbitMQ and configured the management plugin as per the instructions on the website https www r
  • RabbitMQ - 如何死信/处理过期队列中的消息?

    我有一个队列x expires放 我遇到的问题是我需要对队列中的消息进行进一步处理IF队列过期 我最初的想法是设置x dead letter exchange在队列中 但是 当队列过期时 消息就会消失而不会进入死信交换 如何处理死信或以其他
  • Amazon EC2 实例上和本地的 RabbitMQ?

    是否可以设置一个RabbitMQ服务器上的Amazon EC2 instance 并将我办公室的机器连接到此RabbitMQ服务器并向其发送 接收消息 我会被收取费用吗Amazon对于流入 流出我的带宽 消息RabbitMQ EC2 ins
  • 生产者/消费者的不同语言

    我想知道是否可以通过 AMQP 和 RabbitMQ 对生产者和消费者使用不同的语言 例如 Java 代表生产者 python php 代表消费者 或者反之亦然 是的 AMQP 与语言无关 这意味着只要您有可以连接到 AMQP 的客户端sa

随机推荐

  • sql实现截取字段内容

    场景 出现一批数据需要修复 调用方法进行传参 而存储该字段内容是JSONString呈现 所需的仅仅是其中的某一部分数据 因此需要完成截取 并拼接成想要的格式 使用如下格式调用postman实现自动化执行接口调用 例如 taskId xxx
  • 用GCC生成和调用dll【C语言版】

    今天在网上找了好久 才找到这个能成功运行的视频教程 现在分享给大家 Windows下C语言使用GCC编写和调用dll https www bilibili com video BV1E4411z7Ua share source copy w
  • 颜色识别的实例二

    原图 识别结果 代码 color fuses hdev classify fuses by color dev update window off step set up fuse properties and hue ranges Fus
  • iwebsec靶场 SQL注入漏洞通关笔记6- 宽字节注入

    系列文章目录 iwebsec靶场 SQL注入漏洞通关笔记1 数字型注入 mooyuan的博客 CSDN博客 iwebsec靶场 SQL注入漏洞通关笔记2 字符型注入 宽字节注入 mooyuan的博客 CSDN博客 iwebsec靶场 SQL
  • (十七)QT生成PDF文件

    在实际情况中 我们有时候会遇到需要把txt html或者图片变成PDF文件的情况 例如把检测结果生成PDF文档给客户等等 QT4使用QPrinter来实现这个功能 QT5修改为QPdfWriter这个类 一 QT5的修改 如果你想在QT5中
  • 思岚RPLIDAR A2 在ubuntu 16.04上的测试

    1 下载雷达ROS包 首先在github上下载rplidar的ros包 下载指令为 默认安装了git git clone https github com Slamtec rplidar ros git 在ubuntu上创建工作空间 并将该
  • 落地领域大模型应知必会(2): 轻量化微调

    编者按 在实际部署大模型的过程中可能会面临资源限制的问题 通过轻量化大模型微调技术 可以将大型预训练语言模型适配到特定领域 特定任务 并减小其模型尺寸和计算量需求 提高性能和效率 在上一篇文章中 我们分享了大语言模型的主要微调技术总览 接下
  • 实验6-6 使用函数验证哥德巴赫猜想 (20分)

    http pta patest cn pta test 13 exam 3 question 478 include
  • iOS 关于NSNotificationCenter

    通常我们在 iOS 中发生什么事件时该做什么是由 Delegate 实现的 Apple 还为我们提供了另一种通知响应方式 那就是 NSNotification NSNotificationCenter 较之于 Delegate 可以实现更大
  • 计算机视觉OpenCV-图像直方图

    欢迎来到本博客 作者简介 目前计算机研究生在读 主要研究方向是人工智能和群智能算法方向 目前熟悉python网页爬虫 机器学习 计算机视觉 OpenCV 群智能算法 然后正在学习深度学习的相关内容 以后可能会涉及到网络安全相关领域 毕竟这是
  • 100家企业近年面试题整理

    打造最受企业欢迎的iOS开发者 一直都存在的问题 什么样的员工最受企业欢迎 一直也有人在努力提升自己 成为受企业欢迎的员工 然而 我们应该往方向去提升自己呢 100家知名企业今年来iOS面试题合集 你要的这里都有 企业要的这里也有 从基础开
  • Unity Resources资源管理的优点和痛点

    1 1 Resources详解 我觉得 Resources之所以能被广泛的使用 是因为它的使用非常简单 并且是同步加载 一般来说 正式的商业项目 对外发布资源的时候都是使用AssetBundles的方式进行 AssetBundles的方式有
  • re.compile(pattern,flags=0)中flags的用法

    re正则表达式模块还包括一些有用的操作正则表达式的函数 下面主要介绍compile函数 定义 compile pattern flags 根据包含正则表达式的字符串创建模式对象 通过python的help函数查看compile含义 1 he
  • 【数电】如何使用74LS112(或74LS74)构成一个十四分频器(模七计数器)

    IT精英们 大家都学过数字电子技术吧 尽管这东西没用 不过这些基础课程对思维的培养还是很有好处的 我不爱上课 但不代表我不喜欢数电 我们实验课老师为了加强实验难度 把实验题改掉了 用74LS112 或者74LS74 设计一个十四分频器 原来
  • PHP文件包含

    本地文件包含 打开PHPstudy 打开网站根目录 创建文件 文件内容为 在浏览器上查看所包含文件 远程文件包含 文件include php文件内容 print txt文件内容 远程查看print txt 远程包含shell shell t
  • zookeeper入门到精通03——zookeeper集群搭建

    zookeeper集群搭建 3 1 多虚拟机环境搭建 3 2 zookeeper集群搭建 3 1 多虚拟机环境搭建 我们需要搭建zookeeper集群 而由于zookeeper的的服务器数量需要设置为单数 前文介绍了原因 一个zookeep
  • 2023年第47届(第二届)浙江技能大赛网络安全项目 (世赛省选拔赛)A模块解析

    2023年第47届 第二届 浙江技能大赛网络安全项目 世赛省选拔赛 A模块解析 模块A 企业基础设施安全 1 竞项赛目简介 1 1 介绍 1 2 任务描述 1 3 竞赛说明 2 竞赛项目工作任务 2 2 操作系统安全加固 2 2 1 Win
  • OpenCV3.4.13+OpenCV_contrib 双摄像头实时拼接 环境配置

    如题 基于OpenCV3 4 13 VS2015做了个双摄像头实时拼接的代码 是一个大项目的一个baseline的一部分 下面先说配环境再给代码 环境配置 关于OpenCV VS的环境配置网上已经有很多了 因为这份代码用到了OpenCV C
  • 【微信小程序】实现根据某一属性值分类渲染数组内容

    需求与效果 实现根据某一属性值分类渲染数组 需求是 数组如下 渲染在页面上时 根据p num值进行分组渲染 p num相同的放在同一容器里 容器外包裹边框 array content 内容1 id 1 p num 1 content 内容2
  • RabbitMQ系列(十一)RabbitMQ进阶-Queue队列详解-延时队列

    RabbitMQ进阶 Queue队列详解 延迟队列 文章目录 RabbitMQ进阶 Queue队列详解 延迟队列 1 延迟队列场景 1 1 场景 2 延迟队列实现方式 3 TTL Exchange实现延迟队列 3 1 初始化死信交换机 3