spring boot + xxl-job 分布式任务调度

news2024/11/18 10:43:28

一、介绍

1、任务调度

1.1、什么是任务调度

我们可以先思考一下下面业务场景的解决方案:

  • 某电商系统需要在每天上午10点,下午3点,晚上8点发放一批优惠券。
  • 某财务系统需要在每天上午10点前结算前一天的账单数据,统计汇总。
  • 某电商平台每天凌晨3点,要对订单中的无效订单进行清理。
  • 12306网站会根据车次不同,设置几个时间点分批次放票。
  • 电商整点抢购,商品价格某天上午8点整开始优惠。
  • 商品成功发货后,需要向客户发送短信提醒。

类似的场景还有很多,我们该如何实现?
以上这些场景,就是任务调度所需要解决的问题。

任务调度顾名思义,就是对任务的调度,它是指系统为了完成特定业务,基于给定时间点,给定时间间隔或者给定执行次数自动执行任务。

1.2、如何实现任务调度

  • 多线程方式实现:
public static void main(String[] args) {    
    //任务执行间隔时间
    final long timeInterval = 1000;
    Runnable runnable = new Runnable() {
        public void run() {
            while (true) {
                //TODO:something
                try {
                    Thread.sleep(timeInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    Thread thread = new Thread(runnable);
    thread.start();
}

上面的代码实现了按一定的间隔时间执行任务调度的功能。

  • Timer方式实现:
public static void main(String[] args){  
    Timer timer = new Timer();  
    timer.schedule(new TimerTask(){
        @Override  
        public void run() {  
           //TODO:something
        }  
    }, 1000, 2000);  //1秒后开始调度,每2秒执行一次
}

Timer 的优点在于简单易用,每个Timer对应一个线程,因此可以同时启动多个Timer并行执行多个任务,同一个Timer中的任务是串行执行。

  • ScheduledExecutor方式实现:
public static void main(String [] agrs){
    ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
    service.scheduleAtFixedRate(
            new Runnable() {
                @Override
                public void run() {
                    //TODO:something
                    System.out.println("todo something");
                }
            }, 1,2, TimeUnit.SECONDS);
}

Java 5 推出了基于线程池设计的 ScheduledExecutor,其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。

Timer 和 ScheduledExecutor 都仅能提供基于开始时间与重复间隔的任务调度,不能胜任更加复杂的调度需求。比如,设置每月第一天凌晨1点执行任务、复杂调度任务的管理、任务间传递数据等等。

  • Quartz方式实现:
public static void main(String [] agrs) throws SchedulerException {
    //创建一个Scheduler
    SchedulerFactory schedulerFactory = new StdSchedulerFactory();
    Scheduler scheduler = schedulerFactory.getScheduler();
    //创建JobDetail
    JobBuilder jobDetailBuilder = JobBuilder.newJob(MyJob.class);
    jobDetailBuilder.withIdentity("jobName","jobGroupName");
    JobDetail jobDetail = jobDetailBuilder.build();
    //创建触发的CronTrigger 支持按日历调度
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("triggerName", "triggerGroupName")
                .startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
                .build();
        //创建触发的SimpleTrigger 简单的间隔调度
        /*SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("triggerName","triggerGroupName")
                .startNow()
                .withSchedule(SimpleScheduleBuilder
                        .simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())
                .build();*/
    scheduler.scheduleJob(jobDetail,trigger);
    scheduler.start();
}

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext){
        System.out.println("todo something");
    }
}

Quartz 是一个功能强大的任务调度框架,它可以满足更多更复杂的调度需求,Quartz 设计的核心类包括 Scheduler, Job 以及 Trigger。其中,Job 负责定义需要执行的任务,Trigger 负责设置调度策略,Scheduler 将二者组装在一起,并触发任务开始执行。Quartz支持简单的按时间间隔调度、还支持按日历调度方式,通过设置CronTrigger表达式(包括:秒、分、时、日、月、周、年)进行任务调度。

2、分布式调度

2.1、什么是分布式调度

通常任务调度的程序是集成在应用中的,比如:优惠卷服务中包括了定时发放优惠卷的的调度程序,结算服务中包括了定期生成报表的任务调度程序,由于采用分布式架构,一个服务往往会部署多个冗余实例来运行我们的业务,在这种分布式系统环境下运行任务调度,我们称之为分布式任务调度,如下图:
在这里插入图片描述

2.2、分布式调度要实现的目标:

不管是任务调度程序集成在应用程序中,还是单独构建的任务调度系统,如果采用分布式调度任务的方式就相当于将任务调度程序分布式构建,这样就可以具有分布式系统的特点,并且提高任务的调度处理能力:

  1. 并行任务调度
    并行任务调度实现靠多线程,如果有大量任务需要调度,此时光靠多线程就会有瓶颈了,因为一台计算机CPU的处理能力是有限的。
    如果将任务调度程序分布式部署,每个结点还可以部署为集群,这样就可以让多台计算机共同去完成任务调度,我们可以将任务分割为若干个分片,由不同的实例并行执行,来提高任务调度的处理效率。
  2. 高可用
    若某一个实例宕机,不影响其他实例来执行任务。
  3. 弹性扩容
    当集群中增加实例就可以提高并执行任务的处理效率。
  4. 任务管理与监测
    对系统中存在的所有定时任务进行统一的管理及监测。让开发人员及运维人员能够时刻了解任务执行情况,从而做出快速的应急处理响应。
  5. 避免任务重复执行
    当任务调度以集群方式部署,同一个任务调度可能会执行多次,比如在上面提到的电商系统中到点发优惠券的例子,就会发放多次优惠券,对公司造成很多损失,所以我们需要控制相同的任务在多个运行实例上只执行一次。

3、XXL-JOB介绍

XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

官网:https://www.xuxueli.com/xxl-job/
文档:https://www.xuxueli.com/xxl-job/往下拉就能看到文档

XXL-JOB主要有调度中心、执行器、任务:
在这里插入图片描述

3.1、调度中心:

  • 负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。
  • 主要职责为执行器管理、任务管理、监控运维、日志管理等。

3.2、任务执行器:

  • 负责接收调度请求并执行任务逻辑。
  • 只要职责是注册服务、任务执行服务(接收到任务后会放入线程池中的任务队列)、执行结果上报、日志服务等。

3.3、任务:

  • 负责执行具体的业务处理。

3.4、执行流程

调度中心与执行器之间的工作流程如下:

  1. 任务执行器根据配置的调度中心的地址,自动注册到调度中心。
  2. 达到任务触发条件,调度中心下发任务。
  3. 执行器基于线程池执行任务,并把执行结果放入内存队列中、把执行日志写入日志文件中。
  4. 执行器消费内存队列中的执行结果,主动上报给调度中心。
  5. 当用户在调度中心查看任务日志,调度中心请求任务执行器,任务执行器读取任务日志文件并返回日志详情。
    在这里插入图片描述

二、搭建XXL-JOB

1、使用官方xxl-job作为调度中心

1.1、拉取源码

GitHub:https://github.com/xuxueli/xxl-job
码云:https://gitee.com/xuxueli0323/xxl-job

项目结构:

  • xxl-job-admin:调度中心。
  • xxl-job-core:公共依赖。
  • xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用)
    • xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式。
    • xxl-job-executor-sample-frameless:无框架版本。
  • doc :文档资料,包含数据库脚本。
    在这里插入图片描述

1.2、配置数据库

  • 生成数据库
    在这里插入图片描述
  • 配置自己的数据库
    在这里插入图片描述

1.3、启动项目,访问

  • 启动

在这里插入图片描述

  • 访问
    调度中心访问地址:http://localhost:8080/xxl-job-admin

  • 登录
    账号密码:admin/123456
    在这里插入图片描述
    在这里插入图片描述

2、配置执行器项目

2.1、需要执行任务的项目引入依赖

<!--xxl-job-->
<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-job-core</artifactId>
    <version>2.3.1</version>
</dependency>

2.2、配置xxl-job

注意配置中的xxl.job.executor.appname这是执行器的应用名,稍后在调度中心配置执行器时要使用。

### 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=default_token
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
xxl.job.executor.appname=testHandler
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
xxl.job.executor.address=
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
xxl.job.executor.ip=127.0.0.1
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
xxl.job.executor.logretentiondays=30

2.3、配置xxl-job的执行器

将xxl-job调度中心的config文件复制到自己的项目中
在这里插入图片描述

2.4、进入调度中心添加执行器

点击新增,填写执行器信息,appname是前边在配置信息时指定的执行器的应用名。
在这里插入图片描述

2.5、启动项目,观察调度中心中的执行器界面

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3、执行任务

3.1、编写任务类

package org.pzz.jobHandler;

import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class SimpleXxlJob {
    @XxlJob("demoJobHandler")
    public void demoJobHandler() throws Exception {
        System.out.println("执行定时任务,执行时间:"+new Date());
    }
}

3.2、调度中心添加任务类

新增任务,JobHandler为@XxlJob中的名称
在这里插入图片描述

3.3、启动任务

  • 启动执行器
    在这里插入图片描述
  • 启动任务

在这里插入图片描述

3.4、查看

在这里插入图片描述

三、分片广播

1、分片广播介绍

1.1、概念

分片广播策略,分片是指是调度中心将集群中的执行器标上序号:0,1,2,3…,广播是指每次调度会向集群中所有执行器发送调度请求,请求中携带分片参数。
在这里插入图片描述

每个执行器收到调度请求根据分片参数自行决定是否执行任务。

另外xxl-job还支持动态分片,当执行器数量有变更时,调度中心会动态修改分片的数量。

1.2、作业分片适用哪些场景呢?

  • 分片任务场景:10个执行器的集群来处理10w条数据,每台机器只需要处理1w条数据,耗时降低10倍;
  • 广播任务场景:广播执行器同时运行shell脚本、广播集群节点进行缓存更新等。

所以,广播分片方式不仅可以充分发挥每个执行器的能力,并且根据分片参数可以控制任务是否执行,最终灵活控制了执行器集群分布式处理任务。

1.3、高级配置-路由策略:

当执行器集群部署时,提供丰富的路由策略,包括:

  • FIRST(第一个):固定选择第一个机器。
  • LAST(最后一个):固定选择最后一个机器。
  • ROUND(轮询):按照顺序每次调度选择一台执行器去调度。
  • RANDOM(随机):随机选择在线的机器。
  • CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上。
  • LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的机器优先被选举。
  • LEAST_RECENTLY_USED(最近最久未使用):最久未使用的机器优先被选举。
  • FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度。
  • BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度。
  • SHARDING_BROADCAST(分片广播):广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务。

2、执行器集群

2.1、SpringBoot项目运行开启多个集群

实例1 在VM options处添加:-Dserver.port=8888 -Dxxl.job.executor.port=9998
实例2 在VM options处添加:-Dserver.port=8889 -Dxxl.job.executor.port=9999

在这里插入图片描述

2.2、查看调度中心注册情况

在这里插入图片描述

3、分片广播任务

3.1、执行的任务

和其他普通任务没有区别,正常配置

    @XxlJob("shardingJobHandler")
    public void shardingJobHandler() throws Exception {
        // 分片序号,从0开始
        int shardIndex = XxlJobHelper.getShardIndex();
        // 分片总数
        int shardTotal = XxlJobHelper.getShardTotal();

        System.out.println("分片序号:"+shardIndex+"  分片总数:"+shardTotal);

    }

3.2、新增分配广播任务

在这里插入图片描述

3.3、启动任务,查看日志

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、任务调度其他问题

1、如何保证多个执行器不会重复执行任务?

执行器收到调度请求后各自己查询属于自己的任务,这样就保证了执行器之间不会重复执行任务。

xxl-job设计作业分片就是为了分布式执行任务,XXL-JOB并不直接提供数据处理的功能,它只会给执行器分配好分片序号并向执行器传递分片总数、分片序号这些参数,开发者需要自行处理分片项与真实数据的对应关系。

下图表示了多个执行器获取视频处理任务的结构:
在这里插入图片描述

每个执行器收到广播任务有两个参数:分片总数、分片序号。每个执行从数据表取任务时可以让任务id 模上 分片总数,如果等于分片序号则执行此任务。

上边两个执行器实例那么分片总数为2,序号为0、1,从任务1开始,如下:

  • 1 % 2 = 1 执行器2执行
  • 2 % 2 = 0 执行器1执行
  • 3 % 2 = 1 执行器2执行

以此类推。

2、保证任务不重复执行

通过作业分片方案保证了执行器之间分配的任务不重复,另外如果同一个执行器在处理一个视频还没有完成,此时调度中心又一次请求调度,为了不重复处理同一个视频该怎么办?

2.1、调度过期策略

首先配置调度过期策略:

查看文档如下:

  • 调度过期策略:
    • 忽略:调度过期后,忽略过期的任务,从当前时间开始重新计算下次触发时间。
    • 立即执行一次:调度过期后,立即执行一次,并从当前时间开始重新计算下次触发时间。

这里我们选择忽略,如果立即执行一次可能会重复调度。
在这里插入图片描述

2.2、阻塞处理策略

再看阻塞处理策略,阻塞处理策略就是当前执行器正在执行任务还没有结束时调度时间到达到,此时该如何处理。

查看文档如下:

  • 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行;
  • 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败;
  • 覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务;

这里选择 丢弃后续调度,避免重复调度。
在这里插入图片描述

2.3、幂等性

要注意保证任务处理的幂等性,什么是任务的幂等性?
任务的幂等性是指:对于数据的操作不论多少次,操作的结果始终是一致的。

执行器接收调度请求去执行任务,要有办法去判断该任务是否处理完成,如果处理完则不再处理,即使重复调度处理相同的任务也不能重复处理相同的具体操作。

什么是幂等性?
它描述了一次和多次请求某一个资源对于资源本身应该具有同样的结果。
幂等性是为了解决重复提交问题,比如:恶意刷单,重复支付等。

解决幂等性常用的方案:

  • 数据库约束,比如:唯一索引,主键。
  • 乐观锁,常用于数据库,更新数据时根据乐观锁状态去更新。
  • 唯一序列号,操作传递一个唯一序列号,操作时判断与该序列号相等则执行。

结束!!!!!!!
hy:12


							爱情是一种精神追求,不只是身体上的吸引或者一时的情感。

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

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

相关文章

那年我头脑发热,选择了自动化,后来我掉入计算机的世界无法自拔

首先&#xff0c;小雅兰是22届高考考生&#xff0c;而且当时填报志愿也没有填报到计算机相关的专业去&#xff0c;小雅兰是自动化专业的学生&#xff0c;是由于一次偶然的机会&#xff0c;了解到了这个行业&#xff0c;对于写代码所带来的成就感&#xff0c;总之&#xff0c;我…

Java013——常见进制以及转换

一、常见进制 十进制 数字组成&#xff1a;0-9这十个数字组成&#xff0c;不能以0开头 进位规则&#xff1a;满10进1 int num1 10;//对应的十进制为10二进制 数字组成&#xff1a;0-1这两个数字组成&#xff0c;以0b或0B开头 进位规则&#xff1a;满2进1 int num2 0b1010;…

华为存储IA篇仿真器搭建

设备清单 编号 设备名 数量 备注 01 Windows系统主机 1台 为VMware提供安装位置 02 VMware软件 1份 提供存储仿真器的部署环境 03 仿真器文件 1份 用于部署estor虚拟机 【注意】&#xff1a;暂无注意事项 一、下载安装文件并配置虚拟机设备清单 1.1…

TypeScript 自定义装饰器

&#xff08;预测未来最好的方法就是把它创造出来——尼葛洛庞帝&#xff09; 装饰器 装饰器一种更现代的代码模式&#xff0c;通过使用的形式注入在属性&#xff0c;寄存器&#xff0c;方法&#xff0c;方法参数和类中&#xff0c;比如在Angular&#xff0c;Nestjs和midway等…

大数据Doris(三十九):Spark Load 注意事项

文章目录 Spark Load 注意事项 Spark Load 注意事项 1、现在Spark load 还不支持 Doris 表字段是String类型的导入,如果你的表字段有String类型的请改成varchar类型,不然会导入失败,提示 type:ETL_QUALITY_UNSATISFIED; msg:quality not good enough to cancel 2、使用Spa…

无敌!我用【C语言】手搓出了一个体系完整的【员工管理系统】还能玩游戏听音乐?(超详细,附完整源码)

博主简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的人。 博主主页&#xff1a;陈童学哦 所属专栏&#xff1a;C语言程序设计实验项目 如果本文对你有所帮助的话&#xff0c;还希望可以点赞&#x1f44d;收藏&#x1f4c2;支持一下…

Linux——IP协议1

目录 协议头格式 如何封装和解包 如何交付&#xff08;分用&#xff09; 报头每一个字段 分片是怎么做到的 应用层解决的是数据使用的问题。 在传输层&#xff0c;网络层&#xff0c;数据链路层&#xff1a;解决的是网络通信的细节&#xff0c;将数据可靠的从A主机跨网络发…

【深入浅出 Spring Security(八)】前后端分离-使用CSRF漏洞保护详讲

CSRF 漏洞保护 一、CSRF 概述二、CSRF 攻击演示三、CSRF 防御令牌同步模式 四、前后端分离使用 CSRFCsrfFilter 源码分析源码一些方法的细究 测试 五、总结 一、CSRF 概述 CSRF&#xff08;Cross-Site Request Forgery 跨站请求伪造&#xff09;&#xff0c;也可称为一键式攻击…

乐盟互动申请纳斯达克IPO上市,募资2000万美元

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;来自北京的程序化广告平台【乐盟互动】近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市&#xff0c;股票代码&#xff08;LIAI&#xff09;&…

SpringBoot社区小区物业管理停车场系统(Java+Layui+MyBatis+Python+Mysql)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;69小区 获取完整源码源文件说明文档数据库文件 项目特色 本项目使用现行主流技术与架构模式&#xff08;控制层、服务层、数据层&#xff09;代码结构清晰&#xff0c;严格遵循模块化、组件化、接口化思想&#xff1b;关…

mysq在RR级别怎么解决不可重复读和幻读

1、定义 不可重复读&#xff1a; 事务1读取一行&#xff0c;事务2然后修改或删除该行数据并且提交事务&#xff0c;事务1再次读取结果不一样&#xff1b; 幻读&#xff1a;事务1按条件读取查询数据&#xff0c;事务2按照同样的条件新增一条或多条数据并且提交事务&#xff0c…

mysql8查看大事务

文章目录 1、查看大事务的原因2、构建测试数据3、模拟大事务场景4、查询mysql的事务5、查询大事务的详情 1、查看大事务的原因 大事务的特点是执行时间长&#xff0c;长期占有锁不释放&#xff0c;导致其他想操作同一行数据的线程阻塞&#xff0c;如果客户端设置了超时时间&am…

单正态总体和双正态总体的假设检验

1.单正态总体和双正态总体的假设检验 笔者之前的相关笔记&#xff1a; 1.正态总体下常见的抽样分布 2.假设检验&#xff08;Hypothesis Testing&#xff09; 个人理解假设检验&#xff1a;先对总体参数提出一个假设值&#xff0c;利用样本信息判断这一假设是采取拒绝该假设还是…

opencv人与摄像头距离检测

参考&#xff1a; https://chtseng.wordpress.com/2018/09/18/%E5%A6%82%E4%BD%95%E4%BC%B0%E7%AE%97%E5%89%8D%E6%96%B9%E4%BA%BA%E7%89%A9%E7%9A%84%E8%B7%9D%E9%9B%A2/ WeChat_20230611160620 1、cv2加载摄像头慢解决方法&#xff0c;单独重新cv2.VideoCapture() https://b…

使用vue进行Lodop打印的一些方法

文章目录 使用Lodop进行打印的一般步骤vue中使用lodopkr-print-designer简介打印模板设计器打印预览模板设计页面安装引入 Lodop是一个JavaScript控件&#xff0c;用于在Web应用程序中进行打印操作。 使用Lodop进行打印的一般步骤 下载Lodop控件&#xff1a;首先&#xff0c;你…

对比学习做了什么?

什么是对比学习&#xff1f; 对比学习貌似处于“无明确定义、有指导原则”的状态 什么是对比学习呢&#xff1f;(这个是微信链接)全文比较长&#xff0c;但是逻辑框架还是不错的。 如果想要更快速的了解什么是对比学习或者说对比学习是怎么做的&#xff0c;可以看SimCLR这个模…

全网最详细,软件测试-性能测试岗面试题总结(大全)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 描述一下你们公司…

论文阅读:Denoising Diffusion Probabilistic Models

论文阅读&#xff1a;Denoising Diffusion Probabilistic Models 最近一两年&#xff0c;在图像生成领域&#xff0c;扩散模型受到了越来越多的关注&#xff0c;特别是随着 DALL-E2 以及 Midjourney 的持续火爆&#xff0c;扩散模型也变得越来越流行&#xff0c;之前很多基于 …

C++ 参数的三种传递方式和应用场景

C 参数的三种传递方式分别是值传递、指针传递和引用传递。 值传递 值传递的实质 将实参的值&#xff08;a、b&#xff09;复制到形参(m、n)相应的存储单元中&#xff0c;即形参和实参分别占用不同的存储单元。 值传递的特点 值传递的特点是单向传递&#xff0c;即主调函数…

Java Web开发实战经典学习过程笔记

Java Web开发实战经典学习简单笔记 第一章 Java Web 开发简介 1.胖客户端程序指的是&#xff0c;当一个程序运行时需要一个单独的客户端程序支持(如&#xff1a;QQ)。瘦客户端程序在操作时不需要任何其他程序的安装(如&#xff1a;登录网上论坛&#xff0c;只需浏览器即可)。 2…