coinex02// 撮合引擎 RingBuffer Disruptor的构建与使用

news2024/10/2 1:37:58

目录

0. 课程视频地址

0.1 撮合引擎课程

0.1 RocketMQ安装

0.3 RocketMQ搭建成功后登录

1. docker 配置rocketmq

2 逻辑树 : 构建RingBuffer -> 使用RingBuffer

2.1 生产者往RingBuffer中放数据 Disruptor把数据推给消费者cpu

2.2 RingBuffer, Disruptor的创建 -> 事件运行机制构建

3. RingBuffer 完整构建 -> Disruptor 和 SpringBoot 整合

3.1 添加依赖

3.2 Disruptor配置文件 // ps:可以配置是否支持多生产者

3.3 Disruptor异常处理类

3.4 事件携带的数据

3.5 Order 减少耦合 新建类 

3.6 Bean 相同价格不同时间订单的订单类 // 不同价格订单 相同价格不同时间订单

3.7 Order 转换成OrderEvent 发送到RingBuffer

3.8 创建一个RingBuffer / 无锁高效的等待策略 / 创建DisruptorTemplate

3.9 接收到了某个消息

3.10 发送消息的Bean

4 使用构建好的RingBuffer 处理数据

4.1 消费者接口 Sink

4.2 开启Stream 配置

4.2 监听消息 -> 数据库查询 -> 构建order ->发送到ringbuf 队列

5. 数据展示


0. 课程视频地址

0.1 撮合引擎课程

https://www.bilibili.com/video/BV13v4y1A7qH?p=48&vd_source=ff8b7f852278821525f11666b36f180a

0.1 RocketMQ安装

https://www.bilibili.com/video/BV173411P7M2?p=10&vd_source=ff8b7f852278821525f11666b36f180a

0.3 RocketMQ搭建成功后登录

http://rocket-server:8080/#/


1. docker 配置rocketmq

cd /usr/local
mkdir rocketmq
cd rocketmq
vi broker.conf
// 配置 broker.conf

terName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
brokerIP1 = 公网ip

2 逻辑树 : 构建RingBuffer -> 使用RingBuffer

2.1 生产者往RingBuffer中放数据 Disruptor把数据推给消费者cpu

1. 生产者往RingBuffer 放入数据
创建RingBuffer(设置参数:1事件工厂, 2线程工厂, 3等待策略, 4消费者们交易对们) {}
2. Disruptor把数据推给消费者cpu
return new DisruptorTemplate(ringBuffer)

2.2 RingBuffer, Disruptor的创建 -> 事件运行机制构建


创建RingBuffer(设置参数:1事件工厂, 2线程工厂, 3等待策略, 4消费者们交易对们) 
               {
                new Disruptor
                异常处理
                设置消费者
                启动
                停机
                }

new Disruptor (设置参数: 1事件工厂 , 2RingBuffer大小,  3线程工厂, 4生产者类型 ,5等待策略)

disruptor.setDefaultExceptionHandler(new DisruptorHandlerException()); // 异常处理

disruptor.handleEventsWith(eventHandlers);// 设置消费者 交易对

disruptor.start();// 开始监听 //启动

停机策略 停机线程
// 1. 事件工厂

 @Bean //该方法返回一个对象,该对象将被Spring容器管理和提供给其他程序组件使用
    public EventFactory<OrderEvent> eventEventFactory() {

        EventFactory<OrderEvent> orderEventEventFactory = new EventFactory<OrderEvent>() {
            @Override // 重载(Overload)和重写(Override)的区别 重写是子类对父类的允许访问的方法的实现过程进行重新编写被标注的方法重载了父类的方法,起到了断言的作用
            // https://baijiahao.baidu.com/s?id=1715051808653426749&wfr=spider&for=pc
            public OrderEvent newInstance() {
                return new OrderEvent();
            }
        };
        return orderEventEventFactory;
    }
// 2. 线程工厂
@Bean // 有 加依赖cpu 亲和锁 抢占cpu
    public ThreadFactory threadFactory() {
        return new AffinityThreadFactory("Match-Handler:") ;
    }
// 3. 无锁高效的等待策略

    @Bean
    public WaitStrategy waitStrategy() {
        return new YieldingWaitStrategy();
    }
//4. 消费者 交易对们 -> 接受事件 处理事件
@Data
@Slf4j
public class OrderEventHandler implements EventHandler<OrderEvent> { // 为了实现EventHandler 默认的onEvent方法 

    private OrderBooks orderBooks;

    private String symbol ;

    public OrderEventHandler(OrderBooks orderBooks) { // 构造器
        this.orderBooks = orderBooks;
        this.symbol =  this.orderBooks.getSymbol() ;
    }

    @Override
    public void onEvent(OrderEvent event, long sequence, boolean endOfBatch) throws Exception {
        // 从ringbuffer 里面接收了某个数据
        Order order = (Order)event.getSource(); // 强制转换成order
        if(!order.getSymbol().equals(symbol)){ // 我们接收到了一个不属于我们处理的数据,我们不处理
            return;
        }

        log.info("开始接收订单事件============>{}", event);

        MatchServiceFactory.getMatchService(MatchStrategy.LIMIT_PRICE).match(orderBooks ,order);

        log.info("处理完成我们的订单事件===================>{}", event);
    }
}
//5. 消息发送
@Bean // 消息发送对象
    public DisruptorTemplate disruptorTemplate(RingBuffer<OrderEvent> ringBuffer) {
        return new DisruptorTemplate(ringBuffer);
    }

3. RingBuffer 完整构建 -> Disruptor 和 SpringBoot 整合

3.1 添加依赖

<!--match-server-->
<!--        disruptor 高速队列-->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
        </dependency>

        <!--        cpu亲和锁 父项目要加版本-->
        <dependency>
            <groupId>net.openhft</groupId>
            <artifactId>affinity</artifactId>
            <version>${affinity.version}</version>
        </dependency>

        <!--        spring-cloud-stream-rocketmq 消息队列-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
        </dependency>

3.2 Disruptor配置文件 // ps:可以配置是否支持多生产者

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "spring.disruptor")
public class DisruptorProperties {


    /**
     * 缓冲区的大小
     */
    private Integer ringBufferSize = 1024 * 1024 ;

    /**
     * 是否支持多生产者
     */
    private boolean isMultiProducer = false ;
}

3.3 Disruptor异常处理类

package org.example.disruptor;


import com.lmax.disruptor.BatchEventProcessor;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.ExceptionHandler;
import com.lmax.disruptor.LifecycleAware;
import lombok.extern.slf4j.Slf4j;

/**
 * DisruptorHandlerException 的异常处理
 */
@Slf4j
public class DisruptorHandlerException implements ExceptionHandler {


    /**
     * <p>Strategy for handling uncaught exceptions when processing an event.</p>
     *
     * <p>If the strategy wishes to terminate further processing by the {@link BatchEventProcessor}
     * then it should throw a {@link RuntimeException}.</p>
     *
     * @param ex       the exception that propagated from the {@link EventHandler}.
     * @param sequence of the event which cause the exception.
     * @param event    being processed when the exception occurred.  This can be null.
     */
    @Override
    public void handleEventException(Throwable ex, long sequence, Object event) {
        log.info("handleEventException Exception===>{} , sequence==> {} ,event===>{}",ex.getMessage(),sequence,event);
    }

    /**
     * Callback to notify of an exception during {@link LifecycleAware#onStart()}
     *
     * @param ex throw during the starting process.
     */
    @Override
    public void handleOnStartException(Throwable ex) {
        log.info("OnStartHandler Exception===>{} ",ex.getMessage());
    }

    /**
     * Callback to notify of an exception during {@link LifecycleAware#onShutdown()}
     *
     * @param ex throw during the shutdown process.
     */
    @Override
    public void handleOnShutdownException(Throwable ex) {
        log.info("OnShutdownHandler Exception===>{} ",ex.getMessage());
    }
}

3.4 事件携带的数据

import lombok.Data;

import java.io.Serializable;

@Data
public class OrderEvent implements Serializable {

    /**
     * 时间戳
     */
    private final long timestamp;

    /**
     * 事件携带的数据
     */
    protected transient Object source;

    public OrderEvent() {
        this.timestamp = System.currentTimeMillis();
    }

    public OrderEvent(Object source) {
        this.timestamp = System.currentTimeMillis();
        this.source = source ;
    }
}

3.5 Order 减少耦合 新建类 

import lombok.Data;
import lombok.NoArgsConstructor;
import org.example.enums.OrderDirection;

import java.io.Serializable;
import java.math.BigDecimal;

/**
 * 委托单
 */
@Data
@NoArgsConstructor
public class Order implements Serializable {

    /**
     * 本次订单的Id
     */
    private String orderId;

    /**
     * 用户/会员Id
     */
    private Long userId;

    /**
     * 支持的币币交易对
     */
    private String symbol;

    /**
     * 买入或卖出量
     */
    private BigDecimal amount = BigDecimal.ZERO;

    /**
     * 成交量
     */
    private BigDecimal tradedAmount = BigDecimal.ZERO;

    /**
     * 成交额
     */
    private BigDecimal turnover = BigDecimal.ZERO;

    /**
     * 币单位
     */
    private String coinSymbol;

    /**
     * 结算单位
     */
    private String baseSymbol;

    /**
     * 订单状态
     */
    private Integer orderStatus;

    /**
     * 订单的方向
     */
    private OrderDirection orderDirection;

    /**
     * 挂单的价格
     */
    private BigDecimal price = BigDecimal.ZERO;

    /**
     * 挂单时间
     */
    private Long time;

    /**
     * 交易完成时间
     */
    private Long completedTime;

    /**
     * 交易取消时间
     */
    private Long cancelTime;

    private boolean isCancelOrder ;

//    /**
//     * 已经成功的水平订单
//     */
//    private List<OrderDetail> details;


    /**
     * 订单是否完成的判断依据
     *
     * @return
     */
    public boolean isCompleted() {
        return amount.compareTo(tradedAmount) <= 0;
    }
}

3.6 Bean 相同价格不同时间订单的订单类 // 不同价格订单 相同价格不同时间订单

import lombok.Data;

import java.math.BigDecimal;

@Data
public class OrderDetail {
    /**
     * 订单Id
     */
    private String orderId;

    /**
     * 成交价格
     */
    private BigDecimal price;

    /**
     * 成交数量
     */
    private BigDecimal amount;

    /**
     * 成交额
     */
    private BigDecimal turnover;

    /**
     * 费率
     */
    private BigDecimal fee;

    /**
     * 成功时间
     */
    private Long dealTime;

}

3.7 Order 转换成OrderEvent 发送到RingBuffer

import com.lmax.disruptor.EventTranslatorOneArg;
import com.lmax.disruptor.RingBuffer;
import org.example.model.Order;

/**
 * 在boot里面使用它发送消息
 */
public class DisruptorTemplate {

    private static final EventTranslatorOneArg<OrderEvent, Order> TRANSLATOR = new EventTranslatorOneArg<OrderEvent, Order>() {

        public void translateTo(OrderEvent event, long sequence, Order input) {
            event.setSource(input);
        }
    };
    private final RingBuffer<OrderEvent> ringBuffer;

    public DisruptorTemplate(RingBuffer<OrderEvent> ringBuffer) {
        this.ringBuffer = ringBuffer;
    }

    /**
     * 我们使用DisruptorTemplate 时,就使用它的onData方法
     * @param input
     */
    public void onData(Order input) {
        ringBuffer.publishEvent(TRANSLATOR, input);
    }
}

3.8 创建一个RingBuffer / 无锁高效的等待策略 / 创建DisruptorTemplate

import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import net.openhft.affinity.AffinityThreadFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ThreadFactory;

@Configuration
@EnableConfigurationProperties(value = DisruptorProperties.class)
public class DisruptorAutoConfiguration {

    public DisruptorProperties disruptorProperties;

    public DisruptorAutoConfiguration(DisruptorProperties disruptorProperties) {
        this.disruptorProperties = disruptorProperties;
    }


    @Bean
    public EventFactory<OrderEvent> eventEventFactory() {

        EventFactory<OrderEvent> orderEventEventFactory = new EventFactory<OrderEvent>() {
            @Override
            public OrderEvent newInstance() {
                return new OrderEvent();
            }
        };
        return orderEventEventFactory;
    }


    @Bean
    public ThreadFactory threadFactory() {
        return new AffinityThreadFactory("Match-Handler:") ;
    }


    /**
     * 无锁高效的等待策略
     *
     * @return
     */
    @Bean
    public WaitStrategy waitStrategy() {
        return new YieldingWaitStrategy();
    }

    /**
     * 创建一个RingBuffer
     * eventFactory: 事件工厂
     * threadFactory:   我们执行者(消费者)的线程该怎么创建
     * waitStrategy : 等待策略: 当我们ringBuffer 没有数据时,我们怎么等待
     */
    @Bean
    public RingBuffer<OrderEvent> ringBuffer(
            EventFactory<OrderEvent> eventFactory,
            ThreadFactory threadFactory,
            WaitStrategy waitStrategy,
            EventHandler<OrderEvent>[] eventHandlers
    ) {

        /**
         * 构建disruptor
         */
        Disruptor<OrderEvent> disruptor = null;

        ProducerType producerType = ProducerType.SINGLE;

        if (disruptorProperties.isMultiProducer()) {
            producerType = ProducerType.MULTI;
        }

        disruptor = new Disruptor<OrderEvent>(eventFactory, disruptorProperties.getRingBufferSize(), threadFactory, producerType, waitStrategy);
        disruptor.setDefaultExceptionHandler(new DisruptorHandlerException());

        // 设置消费者---我们的每个消费者代表我们的一个交易对,有多少个交易对,我们就有多少个eventHandlers ,事件来了后,多个eventHandlers 是并发执行的

        disruptor.handleEventsWith(eventHandlers);

        RingBuffer<OrderEvent> ringBuffer = disruptor.getRingBuffer();
        disruptor.start();// 开始监听


        final Disruptor<OrderEvent> disruptorShutdown = disruptor;

        // 使用优雅的停机
        Runtime.getRuntime().addShutdownHook(new Thread(
                () -> {
                    disruptorShutdown.shutdown();
                }, "DisruptorShutdownThread"
        ));
        return ringBuffer;
    }


    /**
     * 创建DisruptorTemplate
     *
     * @param ringBuffer
     * @return
     */
    @Bean
    public DisruptorTemplate disruptorTemplate(RingBuffer<OrderEvent> ringBuffer) {
        return new DisruptorTemplate(ringBuffer);
    }
}

3.9 接收到了某个消息

import com.lmax.disruptor.EventHandler;
import org.example.match.MatchServiceFactory;
import org.example.match.MatchStrategy;
import org.example.model.Order;
import org.example.model.OrderBooks;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;


/**
 * 该对象 有多个: 和Symbol的数据对应
 * 针对某一个OrderEventHandler ,只会同一时间有一个线程来执行它
 */
@Data
@Slf4j
public class OrderEventHandler implements EventHandler<OrderEvent> {

    private OrderBooks orderBooks;

    private String symbol ;

    public OrderEventHandler(OrderBooks orderBooks) { // 构造器
        this.orderBooks = orderBooks;
        this.symbol =  this.orderBooks.getSymbol() ;
    }

    /**
     * 接收到了某个消息
     *
     * @param event
     * @param sequence
     * @param endOfBatch
     * @throws Exception
     */
    @Override
    public void onEvent(OrderEvent event, long sequence, boolean endOfBatch) throws Exception {
        // 从ringbuffer 里面接收了某个数据
        Order order = (Order)event.getSource();
        if(!order.getSymbol().equals(symbol)){ // 我们接收到了一个不属于我们处理的数据,我们不处理
            return;
        }

//        log.info("开始接收订单事件============>{}", event);
        /// 处理逻辑是啥?
        MatchServiceFactory.getMatchService(MatchStrategy.LIMIT_PRICE).match(orderBooks ,order);
//

//        log.info("处理完成我们的订单事件===================>{}", event);
    }
}

3.10 发送消息的Bean

/**
     * 创建DisruptorTemplate
     *
     * @param ringBuffer
     * @return
     */
    @Bean
    public DisruptorTemplate disruptorTemplate(RingBuffer<OrderEvent> ringBuffer) {
        return new DisruptorTemplate(ringBuffer);
    }

4 使用构建好的RingBuffer 处理数据

4.1 消费者接口 Sink

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.MessageChannel;


public interface Sink { // 添加数据收发接口

    @Input("order_in")
    MessageChannel messageChannel() ; // MessageChannel 包不要导错 import org.springframework.messaging.MessageChannel;
}

4.2 开启Stream 配置

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.context.annotation.Configuration;


/**
 * 开启我们的Stream的开发
 */
@Configuration
@EnableBinding(value = {Sink.class , Source.class}) // 开启stream 的开发
public class RocketStreamConfig {
}

4.2 监听消息 -> 数据库查询 -> 构建order ->发送到ringbuf 队列

import org.example.disruptor.DisruptorTemplate;

import org.example.domain.EntrustOrder;
import org.example.model.Order;

import lombok.extern.slf4j.Slf4j;
import org.example.util.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MessageConsumerListener { // 消息消费者

    @Autowired
    private DisruptorTemplate disruptorTemplate;

    @StreamListener("order_in") // "order_in" 在 Sink中
    public void handleMessage(EntrustOrder entrustOrder) { // 消息监听
        Order order = null;
        if (entrustOrder.getStatus() == 2) { // 该单需要取消
            order = new Order();
            order.setOrderId(entrustOrder.getId().toString());
            order.setCancelOrder(true);
        } else {
            order = BeanUtils.entrustOrder2Order(entrustOrder);
        }

        log.info("接收到了委托单:{}", order);
        disruptorTemplate.onData(order);// 将order 发送到ringbuf 队列
    }
}

5. 数据展示

https://blog.csdn.net/tenc1239/article/details/130177759?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22130177759%22%2C%22source%22%3A%22tenc1239%22%7D

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

麻了,别再为难测试工程师了...

前言 有不少技术友在测试群里讨论&#xff0c;近期的面试越来越难了&#xff0c;要背的八股文越来越多了,考察得越来越细&#xff0c;越来越底层&#xff0c;明摆着就是想让我们徒手造航母嘛&#xff01;实在是太为难我们这些测试工程师了。 这不&#xff0c;为了帮大家节约时…

Stable Diffusion XL:更快,更强

Stable Diffusion XL&#xff1a;更快&#xff0c;更强 今天&#xff0c;Stability AI 的创始人兼首席执行官 Emad Mostaque 发推宣布&#xff0c;Stable Diffusion XL 进入公测阶段。 核心信息总结起来有2点&#xff1a; “XL”不是新模型的官方名称&#xff0c;Stability …

计算机图形学——游戏方向 第一章 计算机图形学概述

计算机图形学——游戏方向 第一章 计算机图形学概述前言第一章 计算机图形学概述1.为什么设计专业要学习计算机图形学?计算机图形学与计算机视觉等领域的关系计算机图形学基础自学体系2.计算机图形学的辨析3.计算机图形&#xff08;学&#xff09;的发展历史1951&#xff1a;N…

〖Python网络爬虫实战⑭〗- BeautifulSoup详讲

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付费…

Flume系列:Flume Source使用

目录 Apache Hadoop生态-目录汇总-持续更新 1&#xff1a;taildir source 2&#xff1a;kafka source 3&#xff1a;exec source&#xff08;tail -F&#xff09; 4&#xff1a;netcat source&#xff08;采集端口&#xff09; 5&#xff1a;spoolDir读取目录文件&#xf…

Axios请求(对ajax的二次封装)——Axios API、Axios实例、请求配置、Axios响应结构

axios起步——介绍和使用基本用例post请求场景复现核心干货axios APIaxios(config)axios(url[,config])请求方式别名axios实例创建一个axios实例axios.create([config])实例方法axios请求配置axios响应结构场景复现 最近学习与前端相关的小程序时&#xff0c;接触了异步请求ap…

医学图像配准 (Medical Image Registration)

目录 Classification Transformation Registration Algorithms Landmark Based Surfaced Based Voxel Intensity Based Information Theory Based Registration using basis functions Registration using splines Other Physics Based Registration Optimization V…

OctoClock CDA 2990

CDA 2990 CDA 2990为时钟和PPS分发设备&#xff0c;支持外部一路时钟和PPS输入&#xff0c;最高支持8路时钟和PPS输出。同时CDA 2990可选配带GPS模块版本&#xff0c;可外接GPS天线&#xff0c;支持通过GPS锁定时钟和PPS信号输出。CDA 2990主要用于多台USRP设备进行同步。 CDA…

C++之 继承 (inheritance)

目录 启示 一、基本语法 二、继承的方式 三种&#xff1a; 公共基础 / 保护继承 / 私有继承 三、继承中的对象模型 ①父类中所有非静态成员属性都会继承给子类 ②而私有成员属性同样继承过去&#xff0c;但是被编译器隐藏&#xff0c;因此无法访问 四、继承中构造和析…

2023年,送你一份最新的后端架构师知识图谱

这是一个能让你成为架构师的文章&#xff0c;请耐心读完。 为什么写这个 前几天心血来潮搜了下《后端架构师》的技术图谱。发现最新最火的文章更新时间还停留在5年前。最新的技术体系并没有罗列在内。而且文章的颗粒度特别细&#xff0c;是从数据结构和常用算法开始的。这是典…

【加餐 2】Tab 标签页管理

【加餐 2】Tab 标签页管理 对于管理系统,经常需要开启多个标签页,但是每次都需要手动去关闭,很麻烦,所以就有了这个功能,可以一键关闭所有标签页,或者关闭除当前标签页外的所有标签页,对于重要的标签页,可以进行固定至前列,方便下次快速打开。 一、实现效果 实现效…

论文浅尝 | 利用知识图谱增强的Transformer进行跨领域方面抽取

笔记整理&#xff1a;沈小力&#xff0c;东南大学硕士&#xff0c;研究方向为知识图谱链接&#xff1a;https://dl.acm.org/doi/pdf/10.1145/3511808.3557275动机情感分析是自然语言处理的基础任务&#xff0c;它包含介绍了细粒度情感分析中的一个常见任务——基于方面的情感分…

【CSS】鼠标移动到元素上方显示 / 移出盒子范围隐藏案例 ( 子绝父相 | 显示隐藏元素对象 | 鼠标经过样式设置 | 半透明遮罩设置 )

文章目录一、鼠标移动到元素上方显示 / 移出盒子范围隐藏案例要点分析1、子绝父相2、显示隐藏元素对象3、鼠标经过样式设置4、半透明遮罩设置二、代码示例一、鼠标移动到元素上方显示 / 移出盒子范围隐藏案例要点分析 1、子绝父相 这里要 在一个 div 盒子上方套一层遮罩 , 遮罩…

【原理图专题】OrCAD Capture 设计规则(DRC)检查

在原理图设计完成后,需要进行DRC检查,DRC检查能协助工程师快速检查原理图的物理、电气规则是否正确,能快速定位错误和原因。 DRC检查从Capture 工具栏中如下图红框所示的图标中Design Rules Check进入 进入后将打开DRC窗口,有四个选项卡。分别是Design Rules Options、Elec…

带你了解攻击与防护相关知识

目录 一、攻击篇 &#xff11;.什么是恶意软件&#xff1f; &#xff12;.恶意软件有哪些特征&#xff1f; 3. 恶意软件的可分为那几类&#xff1f; 4. 恶意软件的免杀技术有哪些&#xff1f; 5. 反病毒技术有哪些&#xff1f; 6. 反病毒网关的工作原理是什么&#xff1f…

java计时器

在 Java中&#xff0c;我们有一个重要的概念&#xff1a;同步和异步。同步就是 Java中的线程安全&#xff0c;异步就是 Java中的线程非安全。 在使用 JVM时&#xff0c;我们一般都是用 start &#xff08;&#xff09;方法启动一个线程&#xff0c;然后设置时间&#xff0c;比如…

Android开发中,自定义注解的两种应用方式

java注解在Android开发中主要有两种使用方式&#xff1b;一种是在程序运行期间获取类的信息进行反射调用&#xff1b;另一种是使用注解处理&#xff0c;在编译期间生成相关代码&#xff0c;然后在运行期间通过调用这些代码来实现相关功能。 我们先了解一下注解的分类和关键字 …

前端实用js dom合集

1. 整个网页变为灰色主题&#xff0c;最外层加css样式&#xff1a;filter:grayscale(1) 黑色主题&#xff1a;filter&#xff1a;invert(1) 2.js剪辑视频片段制作gif动图&#xff1a; 效果&#xff1a;点击开始就开始录制&#xff0c;点击结束右边显示生成的gif动图 生成g…

Python程序异常处理

一、什么是异常 异常就是程序运行时发生错误的信号&#xff0c;在程序由于某些原因出现错误的时候&#xff0c;若程序没有处理它&#xff0c;则会抛出异常&#xff0c;程序也的运行也会随之终止&#xff1b; 程序异常带来的问题&#xff1a; 1.程序终止&#xff0c;无法运行…

浙大数据结构(1)

开始学习数据结构(拖了好久终于开干了) 来自【浙江大学】数据结构&#xff08;合149讲&#xff09;陈越 何钦铭 Be a Fighter and Keep Fighting!!! 数据结构(data structure)定义 是计算机中存储&#xff0c;组织数据的方法。通常情况下&#xff0c;精心选择的数据结构可以带…