聊聊PowerJob的TimingStrategyHandler

本文主要研究一下PowerJob的TimingStrategyHandler

TimingStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/TimingStrategyHandler.java

public interface TimingStrategyHandler {/*** 校验表达式** @param timeExpression 时间表达式*/void validate(String timeExpression);/*** 计算下次触发时间** @param preTriggerTime 上次触发时间 (not null)* @param timeExpression 时间表达式* @param startTime      开始时间(include)* @param endTime        结束时间(include)* @return next trigger time*/Long calculateNextTriggerTime(Long preTriggerTime, String timeExpression, Long startTime, Long endTime);/*** 支持的定时策略** @return TimeExpressionType*/TimeExpressionType supportType();}

TimingStrategyHandler接口定义了validate、calculateNextTriggerTime、supportType方法

TimeExpressionType

tech/powerjob/common/enums/TimeExpressionType.java

@Getter
@AllArgsConstructor
@ToString
public enum TimeExpressionType {API(1),CRON(2),FIXED_RATE(3),FIXED_DELAY(4),WORKFLOW(5),DAILY_TIME_INTERVAL(11);private final int v;public static final List<Integer> FREQUENT_TYPES = Collections.unmodifiableList(Lists.newArrayList(FIXED_RATE.v, FIXED_DELAY.v));/*** 首次计算触发时间时必须计算出一个有效值*/public static final List<Integer> INSPECT_TYPES =  Collections.unmodifiableList(Lists.newArrayList(CRON.v, DAILY_TIME_INTERVAL.v));public static TimeExpressionType of(int v) {for (TimeExpressionType type : values()) {if (type.v == v) {return type;}}throw new IllegalArgumentException("unknown TimeExpressionType of " + v);}
}

TimeExpressionType枚举定义了API、CRON、FIXED_RATE、FIXED_DELAY、WORKFLOW、DAILY_TIME_INTERVAL几种类型

AbstractTimingStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/AbstractTimingStrategyHandler.java

public abstract class AbstractTimingStrategyHandler implements TimingStrategyHandler {@Overridepublic void validate(String timeExpression) {// do nothing}@Overridepublic Long calculateNextTriggerTime(Long preTriggerTime, String timeExpression, Long startTime, Long endTime) {// do nothingreturn null;}
}

AbstractTimingStrategyHandler实现了TimingStrategyHandler的validate、calculateNextTriggerTime方法

ApiTimingStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/impl/ApiTimingStrategyHandler.java

@Component
public class ApiTimingStrategyHandler extends AbstractTimingStrategyHandler {@Overridepublic TimeExpressionType supportType() {return TimeExpressionType.API;}
}

ApiTimingStrategyHandler继承了AbstractTimingStrategyHandler,其supportType返回的是TimeExpressionType.API

FixedRateTimingStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/impl/FixedRateTimingStrategyHandler.java

@Component
public class FixedRateTimingStrategyHandler extends AbstractTimingStrategyHandler {@Overridepublic void validate(String timeExpression) {long delay;try {delay = Long.parseLong(timeExpression);} catch (Exception e) {throw new PowerJobException("invalid timeExpression!");}// 默认 120s ,超过这个限制应该使用考虑使用其他类型以减少资源占用int maxInterval = Integer.parseInt(System.getProperty(PowerJobDKey.FREQUENCY_JOB_MAX_INTERVAL, "120000"));if (delay > maxInterval) {throw new PowerJobException("the rate must be less than " + maxInterval + "ms");}if (delay <= 0) {throw new PowerJobException("the rate must be greater than 0 ms");}}@Overridepublic Long calculateNextTriggerTime(Long preTriggerTime, String timeExpression, Long startTime, Long endTime) {long r = startTime != null && startTime > preTriggerTime? startTime : preTriggerTime + Long.parseLong(timeExpression);return endTime != null && endTime < r ? null : r;}@Overridepublic TimeExpressionType supportType() {return TimeExpressionType.FIXED_RATE;}
}

FixedRateTimingStrategyHandler继承了AbstractTimingStrategyHandler,其validate方法校验interval参数,要求大于0而且不能大于120s;calculateNextTriggerTime方法先根据startTime、preTriggerTime、timeExpression计算再与endTime做比较;其supportType返回的是TimeExpressionType.FIXED_RATE

FixedDelayTimingStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/impl/FixedDelayTimingStrategyHandler.java

@Component
public class FixedDelayTimingStrategyHandler extends AbstractTimingStrategyHandler {@Overridepublic void validate(String timeExpression) {long delay;try {delay = Long.parseLong(timeExpression);} catch (Exception e) {throw new PowerJobException("invalid timeExpression!");}// 默认 120s ,超过这个限制应该考虑使用其他类型以减少资源占用int maxInterval = Integer.parseInt(System.getProperty(PowerJobDKey.FREQUENCY_JOB_MAX_INTERVAL, "120000"));if (delay > maxInterval) {throw new PowerJobException("the delay must be less than " + maxInterval + "ms");}if (delay <= 0) {throw new PowerJobException("the delay must be greater than 0 ms");}}@Overridepublic TimeExpressionType supportType() {return TimeExpressionType.FIXED_DELAY;}
}

FixedDelayTimingStrategyHandler继承了AbstractTimingStrategyHandler,其validate要求delay大于0且小于等于120s;其supportType返回的是TimeExpressionType.FIXED_DELAY

WorkflowTimingStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/impl/WorkflowTimingStrategyHandler.java

@Component
public class WorkflowTimingStrategyHandler extends AbstractTimingStrategyHandler {@Overridepublic TimeExpressionType supportType() {return TimeExpressionType.WORKFLOW;}
}

WorkflowTimingStrategyHandler继承了AbstractTimingStrategyHandler,其supportType返回的是TimeExpressionType.WORKFLOW

CronTimingStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/impl/CronTimingStrategyHandler.java

@Component
public class CronTimingStrategyHandler implements TimingStrategyHandler {private final CronParser cronParser;/*** @see CronDefinitionBuilder#instanceDefinitionFor* <p>* Enhanced quartz cron,Support for specifying both a day-of-week and a day-of-month parameter.* https://github.com/PowerJob/PowerJob/issues/382*/public CronTimingStrategyHandler() {CronDefinition cronDefinition = CronDefinitionBuilder.defineCron().withSeconds().withValidRange(0, 59).and().withMinutes().withValidRange(0, 59).and().withHours().withValidRange(0, 23).and().withDayOfMonth().withValidRange(1, 31).supportsL().supportsW().supportsLW().supportsQuestionMark().and().withMonth().withValidRange(1, 12).and().withDayOfWeek().withValidRange(1, 7).withMondayDoWValue(2).supportsHash().supportsL().supportsQuestionMark().and().withYear().withValidRange(1970, 2099).withStrictRange().optional().and().instance();this.cronParser = new CronParser(cronDefinition);}@Overridepublic void validate(String timeExpression) {cronParser.parse(timeExpression);}@Overridepublic Long calculateNextTriggerTime(Long preTriggerTime, String timeExpression, Long startTime, Long endTime) {Cron cron = cronParser.parse(timeExpression);ExecutionTime executionTime = ExecutionTime.forCron(cron);if (startTime != null && startTime > System.currentTimeMillis() && preTriggerTime < startTime) {// 需要计算出离 startTime 最近的一次真正的触发时间Optional<ZonedDateTime> zonedDateTime = executionTime.lastExecution(ZonedDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.systemDefault()));preTriggerTime = zonedDateTime.map(dateTime -> dateTime.toEpochSecond() * 1000).orElse(startTime);}Instant instant = Instant.ofEpochMilli(preTriggerTime);ZonedDateTime preZonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());Optional<ZonedDateTime> opt = executionTime.nextExecution(preZonedDateTime);if (opt.isPresent()) {long nextTriggerTime = opt.get().toEpochSecond() * 1000;if (endTime != null && endTime < nextTriggerTime) {return null;}return nextTriggerTime;}return null;}@Overridepublic TimeExpressionType supportType() {return TimeExpressionType.CRON;}
}

CronTimingStrategyHandler实现了TimingStrategyHandler接口,其构造器先创建了CronDefinition,再根据CronDefinition创建CronParser;其validate方法调用了cronParser.parse(timeExpression);calculateNextTriggerTime方法先解析timeExpression,再解析为ExecutionTime,再根据startTime和preTriggerTime计算新的preTriggerTime;最后通过executionTime.nextExecution计算nextTriggerTime;其supportType返回的是TimeExpressionType.CRON

DailyTimeIntervalStrategyHandler

tech/powerjob/server/core/scheduler/auxiliary/impl/DailyTimeIntervalStrategyHandler.java

@Component
public class DailyTimeIntervalStrategyHandler implements TimingStrategyHandler {/*** 使用中国星期!!!*/private static final Set<Integer> ALL_DAY = Sets.newHashSet(1, 2, 3, 4, 5, 6, 7);@Overridepublic TimeExpressionType supportType() {return TimeExpressionType.DAILY_TIME_INTERVAL;}@Override@SneakyThrowspublic void validate(String timeExpression) {DailyTimeIntervalExpress ep = JsonUtils.parseObject(timeExpression, DailyTimeIntervalExpress.class);CommonUtils.requireNonNull(ep.interval, "interval can't be null or empty in DailyTimeIntervalExpress");CommonUtils.requireNonNull(ep.startTimeOfDay, "startTimeOfDay can't be null or empty in DailyTimeIntervalExpress");CommonUtils.requireNonNull(ep.endTimeOfDay, "endTimeOfDay can't be null or empty in DailyTimeIntervalExpress");TimeOfDay startTime = TimeOfDay.from(ep.startTimeOfDay);TimeOfDay endTime = TimeOfDay.from(ep.endTimeOfDay);if (endTime.before(startTime)) {throw new IllegalArgumentException("endTime should after startTime!");}if (StringUtils.isNotEmpty(ep.intervalUnit)) {TimeUnit.valueOf(ep.intervalUnit);}}@Override@SneakyThrowspublic Long calculateNextTriggerTime(Long preTriggerTime, String timeExpression, Long startTime, Long endTime) {DailyTimeIntervalExpress ep = JsonUtils.parseObject(timeExpression, DailyTimeIntervalExpress.class);// 未开始状态下,用起点算调度时间if (startTime != null && startTime > System.currentTimeMillis() && preTriggerTime < startTime) {return calculateInRangeTime(startTime, ep);}// 间隔时间TimeUnit timeUnit = Optional.ofNullable(ep.intervalUnit).map(TimeUnit::valueOf).orElse(TimeUnit.SECONDS);long interval = timeUnit.toMillis(ep.interval);Long ret = calculateInRangeTime(preTriggerTime + interval, ep);if (ret == null || ret <= Optional.ofNullable(endTime).orElse(Long.MAX_VALUE)) {return ret;}return null;}/*** 计算最近一次在范围中的时间* @param time 当前时间基准,可能直接返回该时间作为结果* @param ep 表达式* @return 最近一次在范围中的时间*/static Long calculateInRangeTime(Long time, DailyTimeIntervalExpress ep) {Calendar calendar = Calendar.getInstance();calendar.setTime(new Date(time));int year = calendar.get(Calendar.YEAR);// 月份 + 1,转为熟悉的 1~12 月int month = calendar.get(Calendar.MONTH) + 1;int day = calendar.get(Calendar.DAY_OF_MONTH);// 判断是否符合"日"的执行条件int week = TimeUtils.calculateWeek(year, month, day);Set<Integer> targetDays = CollectionUtils.isEmpty(ep.daysOfWeek) ? ALL_DAY : ep.daysOfWeek;// 未包含情况下,将时间改写为符合条件日的 00:00 分,重新开始递归(这部分应该有性能更优的写法,不过这个调度模式应该很难触发瓶颈,先简单好用的实现)if (!targetDays.contains(week)) {simpleSetCalendar(calendar, 0, 0, 0);Date tomorrowZero = DateUtils.addDays(calendar.getTime(), 1);return calculateInRangeTime(tomorrowZero.getTime(), ep);}// 范围的开始时间TimeOfDay rangeStartTime = TimeOfDay.from(ep.startTimeOfDay);simpleSetCalendar(calendar, rangeStartTime.getHour(), rangeStartTime.getMinute(), rangeStartTime.getSecond());long todayStartTs = calendar.getTimeInMillis();// 未开始if (time < todayStartTs) {return todayStartTs;}TimeOfDay rangeEndTime = TimeOfDay.from(ep.endTimeOfDay);simpleSetCalendar(calendar, rangeEndTime.getHour(), rangeEndTime.getMinute(), rangeEndTime.getSecond());long todayEndTs = calendar.getTimeInMillis();// 范围之间if (time <= todayEndTs) {return time;}// 已结束,重新计算第二天时间simpleSetCalendar(calendar, 0, 0, 0);return calculateInRangeTime(DateUtils.addDays(calendar.getTime(), 1).getTime(), ep);}//......
}    

DailyTimeIntervalStrategyHandler实现了TimingStrategyHandler接口,其supportType返回的是TimeExpressionType.DAILY_TIME_INTERVAL;其validate方法先解析参数为DailyTimeIntervalExpress,然后校验其endTime不能比startTime小;其calculateNextTriggerTime方法主要是通过calculateInRangeTime来计算最近一次在范围中的时间

TimingStrategyService

tech/powerjob/server/core/scheduler/TimingStrategyService.java

@Slf4j
@Service
public class TimingStrategyService {private static final int NEXT_N_TIMES = 5;private static final List<String> TIPS = Collections.singletonList("It is valid, but has not trigger time list!");private final Map<TimeExpressionType, TimingStrategyHandler> strategyContainer;public TimingStrategyService(List<TimingStrategyHandler> timingStrategyHandlers) {// initstrategyContainer = new EnumMap<>(TimeExpressionType.class);for (TimingStrategyHandler timingStrategyHandler : timingStrategyHandlers) {strategyContainer.put(timingStrategyHandler.supportType(), timingStrategyHandler);}}/*** 计算接下来几次的调度时间** @param timeExpressionType 定时表达式类型* @param timeExpression     表达式* @param startTime          起始时间(include)* @param endTime            结束时间(include)* @return 调度时间列表*/public List<String> calculateNextTriggerTimes(TimeExpressionType timeExpressionType, String timeExpression, Long startTime, Long endTime) {TimingStrategyHandler timingStrategyHandler = getHandler(timeExpressionType);List<Long> triggerTimeList = new ArrayList<>(NEXT_N_TIMES);Long nextTriggerTime = System.currentTimeMillis();do {nextTriggerTime = timingStrategyHandler.calculateNextTriggerTime(nextTriggerTime, timeExpression, startTime, endTime);if (nextTriggerTime == null) {break;}triggerTimeList.add(nextTriggerTime);} while (triggerTimeList.size() < NEXT_N_TIMES);if (triggerTimeList.isEmpty()) {return TIPS;}return triggerTimeList.stream().map(t -> DateFormatUtils.format(t, OmsConstant.TIME_PATTERN)).collect(Collectors.toList());}/*** 计算下次的调度时间** @param preTriggerTime     上次触发时间(nullable)* @param timeExpressionType 定时表达式类型* @param timeExpression     表达式* @param startTime          起始时间(include)* @param endTime            结束时间(include)* @return 下次的调度时间*/public Long calculateNextTriggerTime(Long preTriggerTime, TimeExpressionType timeExpressionType, String timeExpression, Long startTime, Long endTime) {if (preTriggerTime == null || preTriggerTime < System.currentTimeMillis()) {preTriggerTime = System.currentTimeMillis();}return getHandler(timeExpressionType).calculateNextTriggerTime(preTriggerTime, timeExpression, startTime, endTime);}/*** 计算下次的调度时间并检查校验规则** @param timeExpressionType 定时表达式类型* @param timeExpression     表达式* @param startTime          起始时间(include)* @param endTime            结束时间(include)* @return 下次的调度时间*/public Long calculateNextTriggerTimeWithInspection( TimeExpressionType timeExpressionType, String timeExpression, Long startTime, Long endTime) {Long nextTriggerTime = calculateNextTriggerTime(null, timeExpressionType, timeExpression, startTime, endTime);if (TimeExpressionType.INSPECT_TYPES.contains(timeExpressionType.getV()) && nextTriggerTime == null) {throw new PowerJobException("time expression is out of date: " + timeExpression);}return nextTriggerTime;}public void validate(TimeExpressionType timeExpressionType, String timeExpression, Long startTime, Long endTime) {if (endTime != null) {if (endTime <= System.currentTimeMillis()) {throw new PowerJobException("lifecycle is out of date!");}if (startTime != null && startTime > endTime) {throw new PowerJobException("lifecycle is invalid! start time must earlier then end time.");}}getHandler(timeExpressionType).validate(timeExpression);}private TimingStrategyHandler getHandler(TimeExpressionType timeExpressionType) {TimingStrategyHandler timingStrategyHandler = strategyContainer.get(timeExpressionType);if (timingStrategyHandler == null) {throw new PowerJobException("No matching TimingStrategyHandler for this TimeExpressionType:" + timeExpressionType);}return timingStrategyHandler;}}

TimingStrategyService的构造器遍历timingStrategyHandlers,然后根据其supportType构建Map<TimeExpressionType, TimingStrategyHandler>;其calculateNextTriggerTimes先根据timeExpressionType获取到对应的TimingStrategyHandler,再循环调用TimingStrategyHandler.calculateNextTriggerTime方法来计算nextTriggerTime,最后返回最近5次的调度时间;calculateNextTriggerTimeWithInspection方法会计算nextTriggerTime并针对CRON及DAILY_TIME_INTERVAL类型的要求其不能为null;validate方法调用的是对应TimingStrategyHandler的validate方法

小结

TimingStrategyHandler接口定义了validate、calculateNextTriggerTime、supportType方法;其支持的TimeExpressionType枚举定义了API、CRON、FIXED_RATE、FIXED_DELAY、WORKFLOW、DAILY_TIME_INTERVAL几种类型,分别对应了ApiTimingStrategyHandler、CronTimingStrategyHandler、FixedRateTimingStrategyHandler、FixedDelayTimingStrategyHandler、WorkflowTimingStrategyHandler、DailyTimeIntervalStrategyHandler;TimingStrategyService则聚合了这些TimingStrategyHandler,对外提供了calculateNextTriggerTimes、calculateNextTriggerTime、calculateNextTriggerTimeWithInspection、validate方法。

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

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

相关文章

ITSS申报条件以及评审方式

01、四级申报基本条件&#xff1a; &#xff08;1&#xff09;具有独立法人地位&#xff1b; &#xff08;2&#xff09;已按照《运维服务能力成熟度》四级特征和关键指标建立了运维服务能力体系&#xff0c;且已有效运行三个月以上&#xff1b; &#xff08;3&#xff09;能…

Spring Boot - Application Events 的发布顺序_ApplicationReadyEvent

文章目录 Pre概述Code源码分析 Pre Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent 概述 Spring Boot 的广播机制是基于观察者模式实现的&#xff0c;它允许在 Spring 应用程序中发布和监听事件。这种机制的主要目的是为了实现解耦&#…

Hades-C2:一款功能强大的纯Python命令控制服务器

关于Hades-C2 Hades-C2是一款功能强大的命令控制服务器&#xff0c;该工具基于纯Python开发&#xff0c;可以帮助广大研究人员快速实现命令控制基础设施的搭建。 当前版本的Hades-C2可以用作安全分析研究或CTF比赛&#xff0c;但功能并不完善&#xff0c;目前该项目仍在积极开…

Java之Stream类

1.介绍 &#xff08;1&#xff09;Stream流 配合Lambda表达式&#xff0c;简化集合和数组的操作 &#xff08;2&#xff09;Stream流思想 流水线思想 2.获取Stream流对象 &#xff08;1&#xff09;集合获取流Stream流对象 使用Collection接口中的默认方法Stream<T> s…

Python学习之路-综合练习:学生管理系统

Python学习之路-综合练习:学生管理系统 目前已经学习了变量、流程控制、函数、模块&#xff0c;可以利用已学习的知识开发一个学生管理系统 项目需求 系统有首页介绍页面与功能菜单系统功能由查询、显示、修改与删除功能可以使用数字选择不同的功能学生信息需要记录&#xf…

Trans论文复现:基于数据驱动的新能源充电站两阶段规划方法程序代码!

适用平台&#xff1a;MatlabYalmipCplex/Gurobi&#xff1b; 文章提出了一种电动汽车充电站的两阶段规划方法&#xff0c;第一阶段通过蒙特卡洛法模拟充电车辆需求和电池充放电数据来确定充电站位置&#xff1b;第二阶段通过数据驱动的分布鲁棒优化方法优化充电站的新能源和电池…

【惠友骨科小课堂】拇外翻常见的几个误区,来看看你中了几个?

拇外翻作为常见的足部畸形&#xff0c;在日常生活中困扰着许多人。歪脚趾不仅外观不好看&#xff0c;还会出现疼痛、影响行走运动。但大多数人对于拇外翻的认识都不足常常落入认知误区&#xff0c;快来看看你中了几个&#xff1f; 误区一Q 我都没穿过高跟鞋&#xff0c;怎么也…

爬虫实战丨基于requests爬取比特币信息并绘制价格走势图

文章目录 写在前面实验环境实验描述实验内容 写在后面 写在前面 本期内容&#xff1a;基于requests爬取比特币信息并绘制价格走势图 下载地址&#xff1a;https://download.csdn.net/download/m0_68111267/88734451 实验环境 anaconda丨pycharmpython3.11.4requests 安装r…

MySQL夯实之路-查询性能优化深入浅出

MySQL调优分析 explain&#xff1b;show status查看服务器状态信息 优化 减少子任务&#xff0c;减少子任务执行次数&#xff0c;减少子任务执行时间&#xff08;优&#xff0c;少&#xff0c;快&#xff09; 查询优化分析方法 1&#xff0e;访问了太多的行和列&#xff1…

pytorch学习笔记(十)

一、损失函数 举个例子 比如说根据Loss提供的信息知道&#xff0c;解答题太弱了&#xff0c;需要多训练训练这个模块。 Loss作用&#xff1a;1.算实际输出和目标之间的差距 2.为我们更新输出提供一定的依据&#xff08;反向传播&#xff09; 看官方文档 每个输入输出相减取…

数据库-列的类型-字符串char类型

char 和 varchar 类型 char 类型懂得都懂就是固定的字符串类型 char (maxLen) 例如 char(5) 这个长度为5 但插入数据‘a’时 是5 插入abc 也是5 即使插满固定 就像C/C语言里 char 字符数组一样 char str[64]; maxLen255 哈哈最多有255个字符多了我认为你是错误 varchar…

C++(9)——内存管理

1. 内存分类&#xff1a; 在前面的文章中&#xff0c;通常会涉及到几个名词&#xff0c;例如&#xff1a;栈、堆。这两个词所代表的便是计算机内存的一部分 。在计算机中&#xff0c;对系统的内存按照不同的使用需求进行了区分&#xff0c;大致可以分为&#xff1a;栈 、堆、数…

Pandas实战100例 | 案例 30: 应用自定义函数

案例 30: 应用自定义函数 知识点讲解 在数据处理过程中&#xff0c;有时需要对数据应用特定的逻辑&#xff0c;这时可以使用自定义函数。Pandas 的 apply 方法允许你对 DataFrame 的行或列应用一个自定义函数。 自定义函数: 你可以定义一个 Python 函数&#xff0c;该函数可…

Debezium发布历史63

原文地址&#xff1a; https://debezium.io/blog/2019/07/08/tutorial-sentry-debezium-container-images/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 将 Sentry 添加到 Debezium 容器镜像的教程 2019 年 7…

安卓11菜单实现hdmi-4K动态切换

客户要求系统实现动态hdmi-4K与普通分辨率直接热切换&#xff0c;先在菜单中做个试验&#xff0c;设置中加个切换开关&#xff0c;点击开关就可以直接切到hdmi-4K&#xff0c;这个功能实现后可以通过插拔hdmi那个状态&#xff08;sys/class/drm/card0-HDMI-A-1/status&#xff…

41k+ stars 闪电般快速的开源搜索引擎 docker安装教程

目录 1.下载 2.启动 成功示例 3.创建索引 4.插入数据 4.1下载数据 4.2插入数据 4.3查看数据 5.官方地址 1.下载 docker pull getmeili/meilisearch:latest 2.启动 mkdir -p /opt/meili_datadocker run -it --rm \-p 7700:7700 \-v /opt/meili_data:/meili_data \ge…

YOLOV7剪枝流程

YOLOV7剪枝流程 1、训练 1&#xff09;划分数据集进行训练前的准备&#xff0c;按正常的划分流程即可 2&#xff09;修改train.py文件 第一次处在参数列表里添加剪枝的参数&#xff0c;正常训练时设置为False&#xff0c;剪枝后微调时设置为True parser.add_argument(--pr…

2401d,讨论d串滑动参数

原文 因为对编译时执行的i串的兴趣,我一直在考虑搞个通用用例,而不是相关i串的用例. 滑动模板参数 请考虑以下模板: void pluto(string s)() {pragma(msg, s); } void test() {pluto!"hello"(); }因为s是编译时参数,这编译,而pragma(msg,s) 期望s为编译时值. voi…

Linux第28步_编译“正点原子的TF-A源码”

编译“正点原子的TF-A源码”&#xff0c;目的是想得到TF-A文件&#xff0c;即“tf-a-stm32mp157d-atk-trusted.stm32”。 在前27步的基础上&#xff0c;才可以学习本节内容&#xff0c;学习步骤如下&#xff1a; 1、创建“alientek_tf-a”目录&#xff1b; 2、复制正点原子的…

.【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)

概率图模型是一种用图形表示概率分布和条件依赖关系的数学模型。概率图模型可以分为两大类&#xff1a;有向图模型和无向图模型。有向图模型也叫贝叶斯网络&#xff0c;它用有向无环图表示变量之间的因果关系。无向图模型也叫马尔可夫网络&#xff0c;它用无向图表示变量之间的…