SpringBoot集成Quartz集群模式

news2024/11/17 15:56:31
		<!-- quartz定时任务 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>

单机版本:

SpringBoot集成Quartz动态定时任务_jobgroupname_小百菜的博客-CSDN博客

集群遇到的问题:

需要注意:集群模式下,最优方案是调度器独立为一个项目,然后再去调度执行器(集群),成熟的解决方案比如xxl-job。

 1、同一个任务在不同节点同时执行。
 2、前端请求,会随机选择一个后台节点,不可控。

解决思路:

1、启动任务和关闭任务时,将任务ID插入一个记录表,并返回版本号(自增主键)。
2、修改任务时,需要先将任务关闭,并插入到记录表。
由于启动任务和关闭任务,是从同一个表的自增主键拿的版本号,所以一定就有先后顺序,可以根据这个先后顺序,判断是否执行任务。

当执行任务时,当前任务版本为最新版本,才可以继续往下执行,否则关闭当前节点的任务。

关键代码:

1、任务调度器

package com.study.job;


import com.study.bean.Task;
import com.study.dao.DemoDao;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 定时任务
 * @author lhs
 * @date 2021年4月30日 下午4:58:24
 */
@Component
public class CronScheduleJob {
    private Logger logger = LoggerFactory.getLogger(CronScheduleJob.class);
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    @Autowired
    private DemoDao demoDao;

    @PostConstruct // 构造函数之后执行
    public void init() {
        //Spring容器加载之后,启动以前的定时任务
        logger.info("启动以前的定时任务");
        List<Task> list = demoDao.getAllTask();
        for (Task task : list) {
            String cron = task.getCron();
            if (cron != null) {
                int id = task.getTaskId();
                //插入任务记录,返回一个版本号
                int version = demoDao.addTaskRecord(id);
                //启动任务
                startTask(id, version, cron);
            }
        }
        logger.info("定时任务启动完成!");
    }

    /**
     * 添加一个定时任务
     * @param jobName          任务名
     * @param jobGroupName     任务组名
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param cron             时间设置,参考quartz说明文档
     * @param params           任务参数
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, String cron, Map<String, Object> params) throws Exception {
        // 任务名,任务组,任务执行类
        JobDetail job = JobBuilder.newJob(ScheduledJob.class).withIdentity(jobName, jobGroupName).build();
        // 触发器,触发器名,触发器组
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName);
        // 触发器时间设定
        CronTrigger trigger = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
        //还可以指定开始执行时间,还可以指定间隔时间,比如cron表达式不能写出每隔50秒执行一次,可以用这种方式。
        //Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2021-05-06 17:10:00");
        //triggerBuilder.startAt(date);
        // 任务参数
        job.getJobDataMap().putAll(params);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        // 调度容器设置Job和Trigger
        scheduler.scheduleJob(job, trigger);
    }

    /**
     * 执行一次
     * @param jobName          任务名
     * @param jobGroupName     任务组名
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param params           任务参数
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void onceJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Map<String, Object> params) throws Exception {
        // 任务名,任务组,任务执行类
        JobDetail job = JobBuilder.newJob(ScheduledJob.class).withIdentity(jobName, jobGroupName).build();
        // 触发器,触发器名,触发器组
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName);
        // 触发器间隔时间和重复时间设定,10这个参数代表指定一个以秒为单位的重复间隔,0这个参数代表指定触发器将重复的次数,总执行次数=重复次数+1
        SimpleTrigger trigger = triggerBuilder.startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).withRepeatCount(0)).build();
        //还可以指定开始执行时间,还可以指定间隔时间,比如cron表达式不能写出每隔50秒执行一次,可以用这种方式。
        //Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2021-05-06 17:10:00");
        //SimpleTrigger trigger = triggerBuilder.startAt(date).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).withRepeatCount(2)).build();
        // 任务参数
        job.getJobDataMap().putAll(params);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        // 调度容器设置Job和Trigger
        scheduler.scheduleJob(job, trigger);
    }

    /**
     * 重复执行
     * @param jobName          任务名
     * @param jobGroupName     任务组名
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param count            重复次数
     * @param params           任务参数
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void repeatJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Integer count, Map<String, Object> params) throws Exception {
        // 任务名,任务组,任务执行类
        JobDetail job = JobBuilder.newJob(ScheduledJob.class).withIdentity(jobName, jobGroupName).build();
        // 触发器,触发器名,触发器组
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName);
        // 触发器间隔时间和重复时间设定,10这个参数代表指定一个以秒为单位的重复间隔,0这个参数代表指定触发器将重复的次数,总执行次数=重复次数+1
        // SimpleTrigger trigger = triggerBuilder.startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).withRepeatCount(0)).build();
        // 间隔时间:withIntervalInSeconds,执行次数:withRepeatCount
        SimpleTrigger trigger = triggerBuilder.startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).withRepeatCount(count - 1)).build();
        //还可以指定开始执行时间,还可以指定间隔时间,比如cron表达式不能写出每隔50秒执行一次,可以用这种方式。
        //Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2021-05-06 17:10:00");
        //SimpleTrigger trigger = triggerBuilder.startAt(date).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).withRepeatCount(2)).build();
        // 任务参数
        job.getJobDataMap().putAll(params);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        // 调度容器设置Job和Trigger
        scheduler.scheduleJob(job, trigger);
    }

    /**
     * 修改一个任务的触发时间
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param cron             时间设置,参考quartz说明文档
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void updateJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, String cron, Map<String, Object> params) throws Exception {
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        if (trigger == null) {
            addJob(jobName, jobGroupName, triggerName, triggerGroupName, cron, params);
            return;
        }
        String oldCron = trigger.getCronExpression();
        if (!oldCron.equalsIgnoreCase(cron)) {
            // 触发器,触发器名,触发器组
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName);
            // 触发器时间设定
            trigger = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
            // 修改一个任务的触发时间
            scheduler.rescheduleJob(triggerKey, trigger);
        }
    }

    /**
     * 移除一个任务
     * @param jobName          任务名
     * @param jobGroupName     任务组名
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void deleteJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) throws Exception {
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        // 停止触发器
        scheduler.pauseTrigger(triggerKey);
        // 移除触发器
        scheduler.unscheduleJob(triggerKey);
        // 删除任务
        scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
    }

    /**
     * 暂停job
     * @param jobName      任务名称
     * @param jobGroupName 任务所在组名称
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void pauseJob(String jobName, String jobGroupName) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        scheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));
    }

    /**
     * 恢复job
     * @param jobName      任务名称
     * @param jobGroupName 任务所在组名称
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void resumeJob(String jobName, String jobGroupName) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        scheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
    }

    /**
     * 启动所有定时任务
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void startAllJobs() throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        scheduler.start();
    }

    /**
     * 关闭所有定时任务
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public void shutdownAllJobs() throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        if (!scheduler.isShutdown()) {
            scheduler.shutdown();
        }
    }

    /**
     * 获取任务是否存在
     *
     * <pre>
     * STATE_BLOCKED 4 阻塞
     * STATE_COMPLETE 2 完成
     * STATE_ERROR 3 错误
     * STATE_NONE -1 不存在
     * STATE_NORMAL 0 正常
     * STATE_PAUSED 1 暂停
     * </pre>
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @author lhs
     * @date 2021年4月30日 下午4:58:24
     */
    public Boolean isExists(String triggerName, String triggerGroupName) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        return scheduler.getTriggerState(TriggerKey.triggerKey(triggerName, triggerGroupName)) == Trigger.TriggerState.NONE;
    }

    /**
     * 启动任务
     * @param id      任务ID
     * @param version 任务版本号
     * @param cron    CRON表达式
     */
    public boolean startTask(int id, int version, String cron) {
        try {
            //新增定时任务
            String jobName = "job" + id;
            String jobGroupName = "group";
            String triggerName = "trigger" + id;
            String triggerGroupName = "group";
            Map<String, Object> params = new HashMap<>();
            params.put("id", id);
            params.put("version", version);
            addJob(jobName, jobGroupName, triggerName, triggerGroupName, cron, params);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }


    /**
     * 停止任务
     * @param id 任务ID
     */
    public boolean stopTask(int id) {
        try {
            //删除定时任务
            String jobName = "job" + id;
            String jobGroupName = "group";
            String triggerName = "trigger" + id;
            String triggerGroupName = "group";
            deleteJob(jobName, jobGroupName, triggerName, triggerGroupName);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }
}

2、任务执行器

package com.study.job;

import com.study.service.TaskService;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 定时任务实现类
 * 注意:该类是非单例的,每次被调用都会生成一个实例来执行。
 * @author lhs
 * @date 2021年4月30日 下午4:58:24
 */
public class ScheduledJob implements Job {
    private static Logger logger = LoggerFactory.getLogger(ScheduledJob.class);
    private static DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    //由于该类实例不是单例,要全局共享使用一个只能使用static来修饰
    public static ExecutorService threadPool = Executors.newFixedThreadPool(16);//线程池,最大线程数为16
    @Autowired
    private TaskService taskService;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        // 传入的参数
        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
        int taskId = mergedJobDataMap.getInt("id");
        int version = mergedJobDataMap.getInt("version");
        long time = jobExecutionContext.getScheduledFireTime().getTime();
        logger.info("执行任务:{},版本号:{},任务计划时间:{}", taskId, version, Instant.ofEpochMilli(time).atZone(ZoneOffset.ofHours(8)).format(fmt));
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                taskService.execTask(taskId, version, time);
            }
        });
    }
}

3、dao层

package com.study.dao;

import com.study.bean.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
 * 示例
 * @author lhs
 * @date 2023/7/3 11:08
 */
@Repository
public class DemoDao {
    private Logger logger = LoggerFactory.getLogger(DemoDao.class);
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 查询任务
     */
    public List<Task> getTaskList() {
        String sql = "select task_id,task_name,cron,status,content from task order by task_id desc";
        return this.jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Task.class));
    }

    /**
     * 查询任务
     */
    public Task getTaskById(int id) {
        String sql = "select task_id,task_name,cron,status,content from task where task_id=? ";
        return this.jdbcTemplate.queryForObject(sql, new Integer[]{id}, new BeanPropertyRowMapper<>(Task.class));
    }

    /**
     * 查询任务
     * 状态:0未启动,1运行中。
     */
    public List<Task> getAllTask() {
        String sql = "select task_id,task_name,cron,status,content from task where status=1 ";
        return this.jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Task.class));
    }

    /**
     * 新增任务
     */
    public int addTask(Task Task) {
        String sql = "insert into task(task_name,cron,status,content) values (?,?,0,?)";
        return this.jdbcTemplate.update(sql, new PreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps) throws SQLException {
                ps.setString(1, Task.getTaskName());
                ps.setString(2, Task.getCron());
                ps.setString(3, Task.getContent());
            }
        });
    }

    /**
     * 修改任务
     */
    public int updateTask(Task Task) {
        String sql = "update task set task_name=?,cron=?,content=?,status=0 where task_id=? ";
        return this.jdbcTemplate.update(sql, new PreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps) throws SQLException {
                ps.setString(1, Task.getTaskName());
                ps.setString(2, Task.getCron());
                ps.setString(3, Task.getContent());
                ps.setInt(4, Task.getTaskId());
            }
        });
    }

    /**
     * 修改任务状态
     */
    public int updateTaskStatus(int status, int id) {
        String sql = "update task set status=? where task_id=? ";
        return this.jdbcTemplate.update(sql, new Integer[]{status, id});
    }

    /**
     * 删除任务
     */
    public int deleteTask(int id) {
        String sql = "delete from task where task_id=? ";
        return this.jdbcTemplate.update(sql, new Integer[]{id});
    }


    /**
     * 插入任务记录
     */
    public int addTaskRecord(int taskId) {
        String sql = "insert into task_record(task_id) values (?)";
        KeyHolder keyHolder = new GeneratedKeyHolder();
        this.jdbcTemplate.update(new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                ps.setInt(1, taskId);
                return ps;
            }
        }, keyHolder);
        return keyHolder.getKey().intValue();
    }

    /**
     * 查询任务最新版本号
     */
    public int getMaxVersion(int taskId) {
        String sql = "select ifnull(max(id),0) from task_record where task_id=? ";
        return jdbcTemplate.queryForObject(sql, new Integer[]{taskId}, Integer.class);
    }
}

4、业务代码

package com.study.service;


import com.study.bean.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 定时任务业务处理
 * @Author: lhs
 * @Date: 2022/6/25 18:18
 */
@Service
public class TaskService {
    private final Logger logger = LoggerFactory.getLogger(TaskService.class);
    @Autowired
    private DemoService demoService;

    /**
     * 执行任务
     * @param taskId  任务ID
     * @param version 任务版本号
     * @param time    计划执行时间
     * @author lhs
     * @date 2022/6/25 21:17
     */
    public void execTask(int taskId, int version, long time) {
        // String lock = taskId + "_" + time;
        // 防止同一个任务在多个节同时执行,还可以将lock插入一个唯一索引字段,插入失败表示这个任务已经在其他节点执行。

        //当前任务版本为最新版本,才可以继续往下执行
        int maxVersion = demoService.getMaxVersion(taskId);
        if (version < maxVersion) {
            //非最新版本,当前版本任务已停止,仅停止当前节点的任务,不能插入任务记录
            demoService.onlyStopTask(taskId);
            logger.warn("当前节点任务非最新版本{},停止任务:{},版本号:{}", maxVersion, taskId, version);
            return;
        }

        logger.info("开始执行业务,当前任务:{},版本号:{}", taskId, version);
        Task task = demoService.getTaskById(taskId);
        // 取到业务数据
        String content = task.getContent();
        // 开始处理业务
        // ....

    }

}

4、涉及表结构

CREATE TABLE `task` (
  `task_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务ID',
  `task_name` varchar(200) NOT NULL COMMENT '任务名',
  `cron` varchar(200) NOT NULL COMMENT 'CRON表达式',
  `status` int(1) NOT NULL DEFAULT '0' COMMENT '状态:0未启动,1运行中。',
  `content` varchar(200) NOT NULL COMMENT '业务内容',
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='任务表'
CREATE TABLE `task_record` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '版本号',
  `task_id` int(11) NOT NULL COMMENT '任务ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COMMENT='任务记录表'

 

示例:

源码:https://gitee.com/gloweds/quartz

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

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

相关文章

CentOS环境下的Nginx安装

Nginx 安装 下载 nginx 下载地址&#xff1a;http://nginx.org/en/download.html 将下载好的压缩包拷贝到根目录下 通过xshell如果出现 bash: rz: 未找到命令 &#xff0c;需要先运行下面的命令 yum -y install lrzsz安装 解压到当前目录 tar -zxvf nginx-1.22.1.tar.gz安…

尚无忧餐桌预订订桌包厢预订小程序源码

1.支持中餐、晚餐不同时间段桌位预定 2.支持包厢&#xff0c;大厅等不同区域预定 本系统后台tpvue 前端原生小程序 <!-- 导航栏 --> <!-- <van-nav-bar title"{{canteen}}" title-class"navbar" /> --> <van-nav-bar title"…

路径规划算法:基于水基湍流优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于水基湍流优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于水基湍流优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化…

springbboot拦截器,过滤器,监听器及执行流程

执行流程 过滤器是在请求进入容器后&#xff0c;但请求进入servlet之前进行预处理的。请求结束返回也是&#xff0c;是在servlet处理完后&#xff0c;返回给前端之前 请求按照上图进入conteoller后执行完再返回 过滤器&#xff08;Filter&#xff09;&#xff1a; 过滤器是S…

Matlab画等构造图

clc;clear;close all; data xlsread(TOPBRENT等T0构造.xlsx); x data(:,1) xmax max(x); xmin min(x); y data(:,2) ymax max(y); ymin min(y); z data(:,3); N 45; …

BeanFactory与ApplicationContext基本介绍

接口定义能力&#xff0c;抽象类实现接口的一些重要方法&#xff0c;最后实现类可以实现自己的一些逻辑 BeanFactory简介 仅仅是一个接口&#xff0c;Spring 的核心容器&#xff0c;并不是IOC容器的具体实现&#xff0c;它的一些具体实现类才是 BeanFactory 与 ApplicationCo…

运动想象MI:带通滤波的Python实现

运动想象MI&#xff1a;带通滤波的Python实现 0. 引言1. 代码介绍1.1 实现方法&#xff08;1&#xff09;1.2 实现方法&#xff08;2&#xff09; 2. 函数介绍3. 滤波函数介绍4. 总结 0. 引言 在执行运动想象任务时&#xff0c;由于实际采集实验不是在完全屏蔽的环境中进行的&…

计算机体系结构基础知识介绍之高级分支预测(一)

由于需要通过分支危险和停顿来强制控制依赖&#xff0c;分支会损害管道性能。 循环展开是减少分支危险数量的一种方法&#xff1b; 我们还可以通过预测分支的行为来减少分支的性能损失。 分支预测是一种计算机技术&#xff0c;它的目的是在执行分支指令之前&#xff0c;预测分支…

人工智能三要素:算法、算力、数据

1 人工智能介绍 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是指计算机系统模拟、模仿和执行人类智能的能力。它是一门研究如何使计算机能够像人类一样思考、学习、推理和解决问题的科学和技术领域。 人工智能通过利用大量的数据和强大的计算…

ACL访问控制、Squid 反向代理

ACL访问控制、Squid 反向代理 一、ACL访问控制1、定义访问控制列表2、配置步骤 二、Squid 反向代理1、工作机制2、配置步骤 一、ACL访问控制 在配置文件 squid.conf 中&#xff0c;ACL 访问控制通过以下两个步骤来实现&#xff1a; &#xff08;1&#xff09;使用 acl 配置项定…

【我们一起60天准备考研算法面试(大全)-第八天 8/60】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

路径规划算法:基于混沌博弈优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于混沌博弈优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于混沌博弈优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化…

Vue3的使用--002

Vue3包含vue2的语法&#xff0c;学习vue3就行。 前提要求&#xff0c; 安装大于node.js15.0。 创建Vue 项目 &#xff1a; npm init Vuelastest : 这一执行将会安装并执行create-vue, 他是Vue 官方的脚手架工具。你将会看到一些Typescript 和测试支持之类的可选功能提示&…

在VSCode里使用Jupyter?Notebook调试Java代码的详细过程

目录 什么是Jupyter Notebook&#xff1f;Jupyter Notebook主要优点环境准备下载 IJava创建conda虚拟环境搭建运行环境测试 之前使用的那台电脑有点旧了&#xff0c;稍微跑一下程序就报内存不够。本来想考虑入手一台带GPU的新电脑&#xff0c;在商品浏览里的时候&#xff0c;…

DynaSLAM代码详解(1) — RGBD模式DynaSLAM运行流程

目录 1.1 DynaSLAM和ORB-SLAM2文件对比 1.2 RGBD模式运行流程 论文翻译地址&#xff1a;动态SLAM论文(2) — DynaSLAM: Tracking, Mapping and Inpainting in Dynamic Scenes_几度春风里的博客-CSDN博客 1.1 DynaSLAM和ORB-SLAM2文件对比 DynaSLAM是一个建立在ORB-SLAM2基础上…

【Leetcode】707. 设计链表

单向链表 class ListNode:def __init__(self, val0, nextNone):self.val valself.next nextclass MyLinkedList:def __init__(self):self.dummy_head ListNode()self.size 0def get(self, index):if index < 0 or index > self.size:return -1current self.dummy_h…

【简单认识LVS+Keepalived负载均衡高可用群集】

文章目录 一、Keepalived高可用详解1、简介2、原理3、Keepalived体系主要模块及其作用&#xff1a; 二、LVSKeepalived 高可用群集部署实例1.配置NFS共享存储器2.配置节点web服务&#xff08;两台的配置相同&#xff09;&#xff08;1&#xff09;配置虚拟 IP 地址&#xff08;…

飞桨黑客松 OpenVINO™ 任务获奖者经验分享 | 基于OpenVINO™ 与PaddleOCR的结构化输出Pipeline...

点击蓝字 关注我们,让开发变得更有趣 作者 | 张一乔 排版 | 李擎 OpenVINO™ 1. 黑客松活动介绍 01 第四季飞桨黑客松(PaddlePaddle Hackathon Season 4)是由百度联合合作伙伴共同举办的开源深度学习框架类黑客松活动。本次活动旨在为全球开发者提供一个交流、合作和创新的机会…

Django_模型类详解(七)

目录 一、定义属性 字段类型 选项 二、查询集 两大特性 查询集的缓存 限制查询集 三、条件查询 条件运算符 1) 查询相等 2) 模糊查询 3) 空查询 4) 范围查询 5) 比较查询 6) 日期查询 F对象 Q对象 聚合函数 四、关联查询 通过对象执行关联查询 通过模型类执…

线程池介绍

1、什么是线程池 例子&#xff1a; 10年前单核CPU电脑&#xff0c;假的多线程&#xff0c;像马戏团小丑玩多个球&#xff0c;CPU需要来回切换。 现在是多核电脑&#xff0c;多个线程各自跑在独立的CPU上&#xff0c;不用切换效率高。 线程池的优势&#xff1a; 线程池做的工作…