当前位置: 首页 > news >正文

apscheduler 定时任务框架

Apscheduler 介绍

四大组件

  • triggers:触发器,用于设定触发任务的条件
  • job stores:作业存储器,用于存放任务,可以存放在数据库或内存,默认内存
  • executors:执行器,用于执行任务,可以设定执行默认为单线程或线程池
  • schedulers:调度器,将上述三个组件作为参数,通过创建调度器实例来执行

触发器 triggers

每个任务都有自己的触发器,它可以决定任务触发的条件,触发器默认是无状态的。

作业存储器 job stores

默认存储在内存中,若存储到数据库中会有个序列化和反序列化的过程,同时修改和搜索任务的功能也是由它实现。

一个作业存储器不要共享给多个调度器,不然会造成状态混乱

执行器 executors

将任务放入线程或线程池中执行,执行完毕通知调度器

调度器 schedulers

调度器提供接口,可以将触发器、作业存储器和执行器整合起来,从而实现对任务的操作。

调度器组件

  • BlockingScheduler 阻塞式调度器:适用于只跑调度器的程序。
  • BackgroundScheduler 后台调度器:适用于非阻塞的情况,调度器会在后台独立运行。
  • AsyncIOScheduler AsyncIO调度器,适用于应用使用AsnycIO的情况。
  • GeventScheduler Gevent调度器,适用于应用通过Gevent的情况。
  • TornadoScheduler Tornado调度器,适用于构建Tornado应用。
  • TwistedScheduler Twisted调度器,适用于构建Twisted应用。
  • QtScheduler Qt调度器,适用于构建Qt应用。

选择正确的调度器、作业存储器、触发器和执行器

1、作业存储器

  • 作业不需要持久化:默认的 MemoryJobStore
  • 作业需要持久化:作业在调度程序重启或应用程序奔溃后继续存在,推荐采用:SQLAlchemyJobStore + PostgreSQL

2、执行器

  • 默认 ThreadPoolExecutor 线程池足以满足大多数场景
  • CPU 密集型操作:应考虑 ProcessPoolExecutor 进程池,来充分利用多核算力。也可以将 ProcessPoolExecutor 作为第二执行器,混合使用两种不同的执行器。

触发器详解

一个任务可以设定多种触发器,如全部条件满足触发、满足其一触发以及复合触发等:

可参考:https://apscheduler.readthedocs.io/en/latest/modules/triggers/combining.html#module-apscheduler.triggers.combining

内置的三种触发器类型

  • date:在特定时间仅允许一次作业
  • interval:固定时间间隔允许作业
  • cron:一天中特定时间定期允许作业

指定时间任务 date

三种类型:date/datetime/字符串,不加时间则立即执行:

from datetime import date, datetimefrom apscheduler.schedulers.blocking import BlockingSchedulersched = BlockingScheduler()def my_job(text):print(text)sched.add_job(my_job, 'date', run_date=date(2009, 11, 6), args=['text'])
sched.add_job(my_job, 'date', run_date=datetime(2020, 1, 7, 14, 35, 2), args=['text'])
sched.add_job(my_job, 'date', run_date='2009-11-06 16:30:05', args=['text'])
sched.add_job(my_job, args=['text'])sched.start()

参考:apscheduler.triggers.date

间隔任务 interval

from datetime import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
import osdef tick():print('当前时间:', datetime.now())if __name__ == '__main__':scheduler = BlockingScheduler()  # 默认调度器,存入在内存中scheduler.add_job(tick, 'interval', seconds=3)  # 添加到作业中print('按 Ctrl+{0} 终端任务'.format('Break' if os.name == 'nt' else 'c  '))try:scheduler.start()except (KeyboardInterrupt, SystemError):pass

运行结果如下:

按 Ctrl+Break 终端任务
当前时间: 2020-01-07 13:55:37.540614
当前时间: 2020-01-07 13:55:40.540879
当前时间: 2020-01-07 13:55:43.542759
当前时间: 2020-01-07 13:55:46.542512
当前时间: 2020-01-07 13:55:49.541907
当前时间: 2020-01-07 13:55:52.541845
当前时间: 2020-01-07 13:55:55.542011
当前时间: 2020-01-07 13:55:58.542533

指定开始、结束时间:

# 指定开始、结束时间
from datetime import date, datetimefrom apscheduler.schedulers.blocking import BlockingSchedulersched = BlockingScheduler()def my_job():print('当前时间:', datetime.now())sched.add_job(my_job, 'interval', seconds=3, start_date='2020-01-07 14:45:20', end_date='2020-01-07 14:46:20')sched.start()

装饰器:

@sched.scheduled_job('interval', id='job_id', seconds=3)
def my_job():print('当前时间:', datetime.now())

jitter 振动参数,给每次触发添加一个随机浮动秒数,一般适用于多服务器,避免同时运行造成服务拥堵。

# 每小时(上下浮动120秒区间内)运行`job_function`
sched.add_job(job_function, 'interval', hours=1, jitter=120)

参考:apscheduler.triggers.interval

crontab表达式 cron

参数

pscheduler.triggers.cron.CronTrigger(year = None,month = None,day = None,week = None,day_of_week = None,hour = None,minutes = None,second = None,start_date = None,end_date = None,timezone = None,jitter = None

参数详解

  • year (int|str) – 4-digit year
  • month (int|str) – month (1-12)
  • day (int|str) – day of the (1-31)
  • week (int|str) – ISO week (1-53)
  • day_of_week (int|str) – number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun)
  • hour (int|str) – hour (0-23)
  • minute (int|str) – minute (0-59)
  • second (int|str) – second (0-59)
  • start_date (datetime|str) :开始触发事件
  • end_date (datetime|str) :结束时间
  • timezone (datetime.tzinfo|str) 用于日期、时间计算的时区,默认为调度程序时区
  • jitter (int|None) :作业最多延迟多久执行

表达式类型

表达式参数类型描述
  • | 所有 | 通配符,minute=* 即每分钟触发一次
    */a | 所有 | 可被 a 整除的通配符
    a-b | 所有 | 范围 a -b 触发
    a-b/c | 所有 | 范围 a-b,且可被 c 整除时触发
    xth y | 日 | 第几个星期几触发,x 为第几个,y 为星期几
    last x | 日 | 一个月中,最后那个星期几触发
    last | 日 | 一个月中最后一天触发
    x,y,z | 所有 | 组合表达式,可组合确定值或上方表达式

示例一

from datetime import date, datetimefrom apscheduler.schedulers.blocking import BlockingSchedulersched = BlockingScheduler()def my_job():print('当前时间:', datetime.now())# 6/7/8 和 11/12 月的第三个周五的 0/1/2/3 点触发
sched.add_job(my_job, 'cron', month='6-8, 11-12', day='3rd fri', hour='0-3')sched.start()

示例二:指定时间范围

# 周一到周日,每天 15::9 触发,截止时间:2020-01-08
sched.add_job(my_job, 'cron', day_of_week='0-6', hour=15, minute=29, end_date='2020-01-08')

示例三:装饰器

# 每个月的最后一个星期日触发
@sched.scheduled_job('cron', id='job_id', day='last 6')
def my_job():print('当前时间:', datetime.now())

示例四:标准 crontab 表达式

sched.add_job(my_job, CronTrigger.from_crontab('0 0 1-15 may-aug *'))

添加 jitter 随机执行,适用于多台服务器在不同时间执行:

# 每小时上下浮动120秒触发
sched.add_job(my_job, 'cron', hour='*', jitter=120)

夏令时问题

有些时区可能因为夏令时问题,导致时区切换时,任务不执行或执行两次,这不是错误,要避免这个问题,可使用 UTC 时间,或提前规避,以下写法可能会导致错误:

# 在Europe/Helsinki时区, 在三月最后一个周一就不会触发;在十月最后一个周一会触发两次
sched.add_job(job_function, 'cron', hour=3, minute=30)

参考:apscheduler.triggers.cron

配置调度器

可通过直接传字典、传参或实例一个调度器对象,再添加配置信息的形式来配置调度器。

创建一个默认作业存储器和执行器:

from apscheduler.schedulers.background import BackgroundSchedulerscheduler = BackgroundScheduler()
  • 调度器:defaultMemoryJonStore (内存任务存储器)
  • 执行器:default ,最大线程数为 10 的 ThreadPoolExecutor 线程池执行器

示例

应用场景:

两个作业存储器搭配两个执行器,同时又要修改作业的默认参数,还有修改时区。

  • 名为 mongo 的 MemoryDBJobStore
  • 名为 default 的 SQLAlchemyJobStore
  • 名为 TreadPoolExecutor 的 ThreadPoolExecutor,最大线程 20
  • 名为 processpool 的 ProcessPoolExecutor,最大进程 5
  • UTC 时区作为默认调度器时区
  • 默认为新任务关闭合并模式
  • 设置新任务的默认最大实例数为 3

1、方法一:

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.mongodb import MongoDBJobStore
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor# 作业存储器
jobstores = {'mongo': MongoDBJobStore(),'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}# 执行器
executors = {'default': ThreadPoolExecutor(20),'processpool': ProcessPoolExecutor(5)
}job_defaults = {'coalesce': False,      # 关闭作业合并'max_instances': 3
}scheduler = BackgroundScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)

2、方法二:

from apscheduler.schedulers.background import BackgroundScheduler# The "apscheduler." prefix is hard coded
scheduler = BackgroundScheduler({'apscheduler.jobstores.mongo': {'type': 'mongodb'},'apscheduler.jobstores.default': {'type': 'sqlalchemy','url': 'sqlite:///jobs.sqlite'},'apscheduler.executors.default': {'class': 'apscheduler.executors.pool:ThreadPoolExecutor','max_workers': '20'},'apscheduler.executors.processpool': {'type': 'processpool','max_workers': '5'},'apscheduler.job_defaults.coalesce': 'false','apscheduler.job_defaults.max_instances': '3','apscheduler.timezone': 'UTC',
})

3、方法三:

from pytz import utcfrom apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ProcessPoolExecutorjobstores = {'mongo': {'type': 'mongodb'},'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
executors = {'default': {'type': 'threadpool', 'max_workers': 20},'processpool': ProcessPoolExecutor(max_workers=5)
}
job_defaults = {'coalesce': False,'max_instances': 3
}
scheduler = BackgroundScheduler()# .. do something else here, maybe add jobs etc.scheduler.configure(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)

启用调度

调用 start() 即可启用调度,对于非阻塞的会立即返回,对于 BlockingScheduler 会阻塞的 start 位置,因此运行其他代码要写在 start 之前。

调度器启动后,就不能修改配置了。

添加任务

  • add_job():返回一个实例对象,通过对象可以修改、删除任务
  • 装饰器:scheduled_job():运行时不能修改任务

任何时候都可添加任务,若调度器未启动,那么任务会处于一个暂存状态。当调度器启动时,才会计算下次运行时间。

若执行器和作业存储器是要序列化的任务的,那么必须满足

  • 回调函数必须全局可用
  • 回调函数参数必须可用被序列化

内置任务储存器中,只有MemoryJobStore不会序列化任务;内置执行器中,只有ProcessPoolExecutor会序列化任务。

另外若程序初始化时,从数据库读取任务,则必须为每个任务定义一个 ID,并使用 replace_existing=True,否则每次重启程序,都会得到一个新的任务拷贝,即前一个任务状态不会被保存。

Tips:立即执行任务,可在添加任务时省略 trigger 参数

移除任务

从调度器移除任务,也必须移除作业存储器中的任务。

  • remove_job(任务 ID):参数为任务 ID 或作业存储器名称
  • 调用 job=add_job()、job.remove() 移除

对于通过 scheduled_job() 创建的任务,只能选择第一种方式。

示例:

job = sched.add_job(func, 'interval', minutes=2)
job.remove()sched.add_job(func, 'interval', minute=2, id='job_id')
sched.remove_job('job_id')

暂停恢复任务

from datetime import date, datetimefrom apscheduler.schedulers.blocking import BlockingSchedulersched = BlockingScheduler()def my_job():print('当前时间:', datetime.now())job = sched.add_job(my_job, 'cron', id='job_id', month='6-8, 11-12', day='3rd fri', hour='0-3')# 暂停作业
job.pause()
sched.pause_job('job_id')# 恢复作业
job.resume()
sched.remove_job('job_id')sched.start()

获取任务列表

from datetime import date, datetimefrom apscheduler.schedulers.blocking import BlockingSchedulersched = BlockingScheduler()def my_job():print('当前时间:', datetime.now())job = sched.add_job(my_job, 'cron', id='job_id', month='6-8, 11-12', day='3rd fri', hour='0-3')print('当前任务', sched.get_job('job_id'))
print('任务列表', sched.get_jobs())
print('格式化作业列表', sched.print_jobs())sched.start()

运行结果如下:

当前任务 my_job (trigger: cron[month='6-8,11-12', day='3rd fri', hour='0-3'], pending)
任务列表 [<Job (id=job_id name=my_job)>]
Pending jobs:my_job (trigger: cron[month='6-8,11-12', day='3rd fri', hour='0-3'], pending)
格式化作业列表 None

print_jobs() 可以快速打印格式化的任务列表,包含触发器,下次运行时间等信息。

修改任务

# 可修改除 ID 以外其他任务属性
job.modify(max_instances=6, name='Alternate name')
sched.modify_job(max_instances=6, name='Alternate name')# 修改触发器
# job.reschedule('job_id', trigger='cron', minute='*/5')
sched.reschedule_job('job_id', trigger='interval', minutes=4)

示例:

from datetime import date, datetimefrom apscheduler.schedulers.blocking import BlockingSchedulersched = BlockingScheduler()def my_job():print('当前时间:', datetime.now())job = sched.add_job(my_job, 'interval', id='job_id', minutes=3)print('当前任务', sched.get_job('job_id'))# job.reschedule('job_id', trigger='cron', minute='*/5')
sched.reschedule_job('job_id', trigger='interval', minutes=4)
print('修改后的任务:', sched.get_job('job_id'))sched.start()

运行结果如下:

当前任务 my_job (trigger: interval[0:03:00], pending)
修改后的任务: my_job (trigger: interval[0:04:00], next run at: 2020-01-07 16:44:45 CST)

关闭调度

sched.shutdown()
sched.shutdown(wait=False)  # 不等待正在运行的任务

限制作业并发执行实例数量

默认情况下,在同一时间,一个任务只允许一个执行中的实例在运行。比如说,一个任务是每5秒执行一次,但是这个任务在第一次执行的时候花了6秒,也就是说前一次任务还没执行完,后一次任务又触发了,由于默认一次只允许一个实例执行,所以第二次就丢失了。为了杜绝这种情况,可以在添加任务时,设置 max_instances 参数,为指定任务设置最大实例并行数。

丢失任务的执行与合并
有时,任务会由于一些问题没有被执行。最常见的情况就是,在数据库里的任务到了该执行的时间,但调度器被关闭了,那么这个任务就成了“哑弹任务”。错过执行时间后,调度器才打开了。这时,调度器会检查每个任务的 misfire_grace_time 参数 int 值,即哑弹上限,来确定是否还执行哑弹任务(这个参数可以全局设定的或者是为每个任务单独设定)。此时,一个哑弹任务,就可能会被连续执行多次。

但这就可能导致一个问题,有些哑弹任务实际上并不需要被执行多次。 coalescing 合并参数就能把一个多次的哑弹任务揉成一个一次的哑弹任务。也就是说,coalescingTrue 能把多个排队执行的同一个哑弹任务,变成一个,而不会触发哑弹事件。

注!如果是由于线程池/进程池满了导致的任务延迟,执行器就会跳过执行。要避免这个问题,可以添加进程或线程数来实现或把 misfire_grace_time 值调高。

调度事件监听

任务执行时有可能会出现错误,那么如何第一时间指定在哪发生错误呢? apscheduler
给我们提供了事件监听来解决这个问题。

from datetime import date, datetimefrom apscheduler.schedulers.blocking import BlockingSchedulersched = BlockingScheduler()def my_job():print('当前时间:', datetime.now())print(1/0)

上述代码每 5 秒钟执行一次,每次都会发生错误。我们给其添加一个回调函数和日志记录来监听:

from datetime import date, datetime
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
import logginglogging.basicConfig(level=logging.INFO,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',datefmt='%Y-%m-%d %H:%M:%S',filename='log.txt',filemode='a')sched = BlockingScheduler()def my_job():print('当前时间:', datetime.now())print(1 / 0)def test_job():print('正常任务!', datetime.now())def my_listener(event):if event.exception:print('任务运行出错!', datetime.now())else:print('任务正常运行!', datetime.now())job = sched.add_job(my_job, 'cron', second='*/5')
job1 = sched.add_job(test_job, 'interval', seconds=3)
sched.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
sched._logger = loggingsched.start()

事件类型

ConstantDescriptionEvent class
EVENT_SCHEDULER_STARTEDThe scheduler was started SchedulerEvent
EVENT_SCHEDULER_SHUTDOWNThe scheduler was shut down SchedulerEvent
EVENT_SCHEDULER_PAUSEDJob processing in the scheduler was paused SchedulerEvent
EVENT_SCHEDULER_RESUMEDJob processing in the scheduler was resumed SchedulerEvent
EVENT_EXECUTOR_ADDEDAn executor was added to the scheduler SchedulerEvent
EVENT_EXECUTOR_REMOVEDAn executor was removed to the scheduler SchedulerEvent
EVENT_JOBSTORE_ADDEDA job store was added to the scheduler SchedulerEvent
EVENT_JOBSTORE_REMOVEDA job store was removed from the scheduler SchedulerEvent
EVENT_ALL_JOBS_REMOVEDAll jobs were removed from either all job stores or one particular job store SchedulerEvent
EVENT_JOB_ADDEDA job was added to a job store JobEvent
EVENT_JOB_REMOVEDA job was removed from a job store JobEvent
EVENT_JOB_MODIFIEDA job was modified from outside the scheduler JobEvent
EVENT_JOB_SUBMITTEDA job was submitted to its executor to be run JobSubmissionEvent
EVENT_JOB_MAX_INSTANCESA job being submitted to its executor was not accepted by the executor because the job has already reached its maximum concurrently executing instances JobSubmissionEvent
EVENT_JOB_EXECUTEDA job was executed successfully JobExecutionEvent
EVENT_JOB_ERRORA job raised an exception during execution JobExecutionEvent
EVENT_JOB_MISSEDA job’s execution was missed JobExecutionEvent
EVENT_ALLA catch-all mask that includes every event type N/A

日志

import logginglogging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.DEBUG)

相关文章:

apscheduler 定时任务框架

Apscheduler 介绍 四大组件 triggers&#xff1a;触发器&#xff0c;用于设定触发任务的条件job stores&#xff1a;作业存储器&#xff0c;用于存放任务&#xff0c;可以存放在数据库或内存&#xff0c;默认内存executors&#xff1a;执行器&#xff0c;用于执行任务&#x…...

Softing OPC Tunnel——绕过DCOM配置实现OPC Classic广域网通信

一 摘要 Softing OPC Tunnel是dataFEED OPC Suite的一个组件&#xff0c;可避免跨设备OPC Classic通信中出现的DCOM配置问题&#xff0c;同时可保证跨网络数据交换的高性能和可靠性。OPC Tunnel内部集成的存储转发功能&#xff0c;可在连接中断时缓存数据&#xff0c;并在重新…...

Java的运算操作

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【JavaSE_primary】 文章目录算术运算符增量运算符注意自增自减运算符关系运算符逻辑运算符逻辑与&&逻辑或||逻辑非&#xff01;…...

基于OBD系统的量产车评估测试(PVE)

在轻型汽车污染物排放限值及测量方法&#xff08;中国第六阶段&#xff09;中&#xff0c;除了对汽车尾气排放等制定了更为严格的限制之外&#xff0c;也在OBD系统认证项目中增加了新的要求——量产车评估&#xff08;Production Vehicle Evaluation&#xff09;测试。该测试由…...

【蓝桥杯集训10】Tire树 字典树 最大异或对专题(3 / 3)

目录 字典树模板 1、插入操作 2、查询操作 143. 最大异或对 - trie 二进制 3485. 最大异或和 - 前缀和Trie滑动窗口 字典树模板 活动 - AcWing 字典树&#xff1a;高效存储和查找字符串集合的数据结构 son[节点1地址][值]节点2地址 —— 节点1的子节点为节点2cnt[节点地…...

docker部署zabbix6.2.7+grafana

目录 1、下载docker 2、下载相关镜像文件 3、创建一个供zabbix系统使用的网络环境 4、创建一个供mysql数据库存放文件的目录 5、启动mysql容器 6、为zabbix-server创建一个持久卷 7、启动zabbix-server容器 8、创建语言存放目录 9、启动zabbix-web容器 10、启动zabbix…...

【Java开发】JUC基础 04:Synchronized、死锁、Lock锁

1 概念介绍并发&#xff1a;同一个对象被多个线程同时操作&#x1f4cc; 线程同步现实生活中&#xff0c;我们会遇到“同一个资源&#xff0c;多个人都想使用”的问题&#xff0c;比如&#xff0c;食堂排队打饭,每个人都想吃饭&#xff0c;最天然的解决办法就是&#xff0c;排队…...

离散数学---期末复习知识点

一、 数理逻辑 [复习知识点] 1、命题与联结词&#xff08;否定&#xffe2;、析取∨、合取∧、蕴涵→、等价↔&#xff09;&#xff0c;命题(非真既假的陈述句),复合命题(由简单命题通过联结词联结而成的命题) 2、命题公式与赋值&#xff08;成真、成假&#xff09;&#x…...

在线安装ESP32和ESP8266 Arduino开发环境

esp32和esp8266都是乐鑫科技开发的单片机产品&#xff0c;esp8266价格便宜开发板只需要十多块钱就可以买到&#xff0c;而esp32是esp8266的升级版本&#xff0c;比esp8266的功能和性能更强大&#xff0c;开发板价格大约二十多元就可以买到。 使用Arduino开发esp32和esp8266需要…...

【Python实战】激情澎湃,2023极品劲爆舞曲震撼全场,爬虫一键采集DJ大串烧,一曲醉人女声DJ舞曲,人人都听醉~(排行榜采集,妙啊~)

导语 哈喽&#xff01;大家好。我是木木子吖~今天给大家带来爬虫的内容哈。 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 今天教大家Python爬虫实战一键采集大家喜欢的DJ舞曲哦&#xff01; …...

[SSD综述 1.5] SSD固态硬盘参数图文解析_选购固态硬盘就像买衣服?

版权声明&#xff1a;付费作品&#xff0c;未经许可&#xff0c;不可转载前言SSD &#xff08;Solid State Drive&#xff09;&#xff0c;即固态硬盘&#xff0c;通常是一种以半导体闪存&#xff08;NAND Flash&#xff09;作为介质的存储设备。SSD 以半导体作为介质存储数据&…...

SAP Insurance Analyzer

SAP Insurance Analyzer 是一款用于保险公司财务和风险管理的软件。SAP Insurance analyzer 支持基于 IFRS 17 或 Solvency II 的保险合同估值和计算要求。SAP Insurance Analyzer 于 2013 年 5 月推出&#xff0c;为源数据和结果数据集成了一个预配置的保险数据模型。 源数据…...

自动化测试 ——自动卸载软件

在平常的测试工作中&#xff0c;经常要安装软件&#xff0c;卸载软件, 即繁琐又累。 安装和卸载完全可以做成自动化。 安装软件我们可以通过自动化框架&#xff0c;自动点击Next,来自动安装。 卸载软件我们可以通过msiexec命令行工具自动化卸载软件 用msiexec 命令来卸载软件 …...

05 封装

在对 context 的封装中&#xff0c;我们只是将 request、response 结构直接放入 context 结构体中&#xff0c;对应的方法并没有很好的封装。 函数封装并不是一件很简单、很随意的事情。相反&#xff0c;如何封装出易用、可读性高的函数是非常需要精心考量的&#xff0c;框架中…...

clean

clean code 记得以前写过这题&#xff0c;写的乱七八糟&#xff0c;分析来分析去。 后悔应该早点写代码&#xff0c;leetcode大一就该刷了。 https://leetcode.cn/problems/plus-one/submissions/ class Solution { public:vector<int> plusOne(vector<int>&…...

佛科院计算机软件技术基础——线性表

一、基础知识了解&#xff1a;结构体的理解&#xff1a;我们知道整型是由1位符号位和15位数值位组成&#xff0c;而就可以把结构体理解为我们定义的数据类型&#xff0c;如&#xff1a;typedef struct {int data[2]; //存储顺序表中的元素int len; …...

linux下终端操作mysql数据库

目录 一&#xff0e;检查mysql是否安装 1. 查看文件安装路径 2. 查询运行文件所在路径(文件夹地址) 二&#xff0e;登录mysql 三&#xff0e;列出mysql全部用户 四&#xff0e;常用指令 &#xff11;&#xff0e;查看全部数据库 &#xff12;&#xff0e;选择数据库 …...

MySQL参数优化之thread_cache_size

1.thread_cache_size简介 每建立一个连接&#xff0c;都需要一个线程来与之匹配&#xff0c;此参数用来缓存空闲的线程&#xff0c;以至不被销毁&#xff0c;如果线程缓存中有空闲线程&#xff0c;这时候如果建立新连接&#xff0c;MYSQL就会很快的响应连接请求。 show statu…...

gRPC服务健康检查(二):gRPC健康检查协议详解

gRPC健康检查协议健康检查用于检测服务端能否正常处理rpc请求&#xff0c;客户端对服务端的健康检查可以点对点进行&#xff0c;也可以通过某些控制系统&#xff08;如负载平衡&#xff09;进行。客户端可以根据服务端返回的状态执行对应的策略。因为GRPC服务可以用于简单的客户…...

Android系统10 RK3399 init进程启动(四十七) Android init 进程整体代码逻辑简述

配套系列教学视频链接&#xff1a;安卓系列教程之ROM系统开发-百问100ask说明系统&#xff1a;Android10.0设备&#xff1a; FireFly RK3399 &#xff08;ROC-RK3399-PC-PLUS&#xff09;前言本文简单描述一下android init祖先进程启动的基本执行流程&#xff0c;让大家有一个整…...

CSDN 编程竞赛三十二期题解

竞赛总览 CSDN 编程竞赛三十二期&#xff1a;比赛详情 (csdn.net) 竞赛题解 题目1、传奇霸业 传奇霸业&#xff0c;是兄弟就来干。小春&#xff08;HP为a&#xff09;遇到了一只黄金哥布林&#xff08;HP为x&#xff09;。小春每次能对哥布林造成b点伤害&#xff0c;哥布林…...

Kubernetes 中的 Pod Hook

Pod Hook 我们知道Pod是Kubernetes集群中的最小单元&#xff0c;而 Pod 是有容器组组成的&#xff0c;所以在讨论 Pod 的生命周期的时候我们可以先来讨论下容器的生命周期。 实际上 Kubernetes 为我们的容器提供了生命周期钩子的&#xff0c;就是我们说的Pod Hook&#xff0c…...

Linux操作系统安装MySQL(rpm安装)

Linux操作系统安装MySQL&#xff08;rpm安装&#xff09;1 背景2 环境说明3 准备工作3.1 端口查看3.2 检查安装3.3 创建MySQL用户和组4 MySQL安装4.1 下载MySQL4.2 解压安装包4.3 安装MySQL4.4 初始化MySQL4.5 启动MySQL4.6 设置MySQL初始密码4.6.1 查看数据库初始密码4.6.2 更…...

MySQL高级第二讲

目录 二、MySQL高级02 2.1 触发器 2.1.1 触发器介绍 2.1.2 创建触发器 2.2 MySQL的体系结构 2.3 存储引擎 2.3.1 存储引擎概述 2.3.2 各种存储引擎特性 2.3.3 InnoDB 2.3.4 MyISAM 2.3.5 MEMORY 2.3.6 MERGE 2.3.7 存储引擎的选择 2.4 优化sql 2.4.1 查看sql执行…...

凸优化专题1

多变量函数的求导与求梯度/矩阵求导 1. 导数 定义: 设f:Rn→Rm,且x∈intdomf,则f在点x的导数(或称Jacobian)记为矩阵Df(x)∈Rmnf:\R^n \rightarrow \R^m, 且x\in \mathbf{int}\ \mathbf{dom} f, 则f 在点x的导\\数(或称Jacobian)记为矩阵 Df(x) \in \R^{m\times n}f:Rn→Rm,且…...

【蓝桥杯每日一题】递推算法

&#x1f34e; 博客主页&#xff1a;&#x1f319;披星戴月的贾维斯 &#x1f34e; 欢迎关注&#xff1a;&#x1f44d;点赞&#x1f343;收藏&#x1f525;留言 &#x1f347;系列专栏&#xff1a;&#x1f319; 蓝桥杯 &#x1f319;我与杀戮之中绽放&#xff0c;亦如黎明的花…...

Unity性能优化: 性能优化之内存篇

前言 本文和传统的内存优化不一样&#xff0c;不是讲如何降低内存占用&#xff0c;而是讲编程开发中要注意的内存问题以及一些内存技术的演变与原理。 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;希望大家可以点击进来一起交流一下开发经验呀 1: Application进程…...

华为OD机试题,用 Java 解【内存资源分配】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…...

微服务之Nacos注册与配置

&#x1f3e0;个人主页&#xff1a;阿杰的博客 &#x1f4aa;个人简介&#xff1a;大家好&#xff0c;我是阿杰&#xff0c;一个正在努力让自己变得更好的男人&#x1f468; 目前状况&#x1f389;&#xff1a;24届毕业生&#xff0c;奋斗在找实习的路上&#x1f31f; &#x1…...

Android 动画详解

Android动画的分类与使用学习Android必不可少的就是动画的使用了&#xff0c;在Android版本迭代的过程中&#xff0c;出现了很多动画框架&#xff0c;这里做一个总结。Android动画类型分类逐帧动画【Frame Animation】&#xff0c;即顺序播放事先准备的图片。补间动画【Tween A…...

如何做阅读网站/网络热词2023流行语及解释

本文参考&#xff1a;《Spring in action》 Spring中bean的生命周期相对比较复杂&#xff0c;因为我们可以利用Spring提供的扩展点来自定义bean的创建过程。 下图展示了bean装载到Spring应用上下文中的一个典型的生命周期过程。bean的后置处理器&#xff1a;•Bean 后置处理器允…...

常州网站制作公司排名/抖音搜索seo排名优化

初级 fun&#xff08;&#xff09; 全局对象window obj.sayName扩展 1this是什么 任何函数本质上都是通过某个对象调用的&#xff0c;如果没有指定就是window 所有函数内部都有一个变量this 它的值是调用函数的当前对象 2如何确定this的值 test&#xff08;&#xff09;…...

织梦cms可以做淘宝客网站么/推广普通话的宣传标语

传送门 题意&#xff1a;给出n个人&#xff0c;然后给出x个限制&#xff0c;这x个限制是dist[v]-dist[u]<w&#xff0c;然后给出y个限制&#xff0c;这y个限制是dist[v]-dist[u]>w&#xff0c;之后如果有解的话输出dist[n]-dist[1]&#xff0c;如果有多个解&#xff0c;…...

网络工作网站/外贸网络营销推广

前言关于异或值怎么计算代码第二种方式&#xff0c;适合不懂怎么计算&#xff0c;想直接用的代码前言偶然看到有可以解密微信dat的文档&#xff0c;上网查了查&#xff0c;找到了一篇可以用的文章&#xff0c;不过转换过程代码是有问题的&#xff0c;在这里改了下发布上来。提取…...

网站设计师图片/品牌推广外包

目录 6.1 实时竞价 6.2 其他程序化交易方式 6.3 广告交易平台 6.4 需求方平台 6.5 供给方平台 程序化交易平台产品&#xff1a; 6.1 实时竞价 &#xff08;1&#xff09;用户标识映射 设计cookie映射 &#xff08;2&#xff09;广告请求RTB 2.1 用户接触到媒体网站广告…...

宝安网站制作培训/辅导班培训机构

WanAndroid 项目地址&#xff1a;iceCola7/WanAndroid 简介&#xff1a; &#x1f525;项目采用 Kotlin 语言&#xff0c;基于 MVP RxJava Retrofit Glide EventBus 等架构设计&#xff0c;努力打造一款优秀的 [玩 Android] 客户端 更多&#xff1a;作者 提 Bug 标…...