前言
在上一篇文章中,简单的捋了一遍使用BackgroundScheduler调度器做定时任务的流程,本篇接着上一篇文章,分析一下_real_add_job
方法和_main_loop
方法。
虽然APScheduler有多种不同的调度器以及多种不同的使用方式,但其核心都是类似的,一通百通。
对了,文中分析的APScheduler是当前最新版3.6.1。
剖析_real_add_job
回顾一下上篇文章添加任务对象的大致逻辑。
实例化BackgroundScheduler --> 调用add_job方法 --> 最终调用_real_add_job
_real_add_job
源码如下,其代码的大致逻辑以给出相应的注释。
# apscheduler/schedulers/base.py/BaseScheduler
def _real_add_job(self, job, jobstore_alias, replace_existing):
"""
将任务对象添加到指定的存储后端中(默认就是内存中-->dict)
"""
# 使用默认值填写未定义的值
replacements = {
}
for key, value in self._job_defaults.items():
if not hasattr(job, key):
replacements[key] = value
# 如果未定义下次运行时间,则计算下次运行时间
if not hasattr(job, 'next_run_time'):
now = datetime.now(self.timezone)
replacements['next_run_time'] = job.trigger.get_next_fire_time(None, now)
# 应用任何替换
job._modify(**replacements)
# 将作业添加到给定的作业库
store = self._lookup_jobstore(jobstore_alias)
try:
store.add_job(job)
except ConflictingIdError:
if replace_existing:
store.update_job(job)
else:
raise
# 将任务对象标记为非待定
job._jobstore_alias = jobstore_alias
# 通知监听器已添加新任务
event = JobEvent(EVENT_JOB_ADDED, job.id, jobstore_alias)
self._dispatch_event(event)
self._logger.info('Added job "%s" to job store "%s"', job.name, jobstore_alias)
# 通知调度程序有关新工作的信息
if self.state == STATE_RUNNING:
self.wakeup()
代码中已有大致的注释,这里再简单分析一下。
一开始定义replacements字典,然后循环处理_job_defaults
字典,判断该字典中的key是否是job任务对象的属性,如果是,则添加到replacements字典中。
接着同样的方式,判断job任务对象是否存在next_run_time属性,如果不存在,则需要调用当前任务对象中触发器(trigger)的get_next_fire_time方法计算出当前任务对象下一次要运行的时间。
随后调用job任务对象_modify
方法,该方法的作用就是修改job任务对象的属性。
怎么实现属性的修改?没想象的那样使用了什么高深的技巧,看该方法的源码,就定义了approved字典,然后将replacements字典中的值获取并判断是否替换,替换就放到approved字典中,最后遍历approved字典,利用setattr方法将该字典中的值设置为job对象的属性,实现job对象属性的修改。
接着调用_lookup_jobstore
方法找到用于存储当前任务对象的job stores(任务存储器),jobstore_alias是_real_add_job
方法的参数,该方法是add_job方法调用的,往回看,可知jobstore_alias默认为default字符串,则选择内存作为job stores,然后调用job sotres的add_job方法将任务对象加入其中。
为啥说job stores为default就是使用内存作为job store呢?
看到BaseScheduler类的start方法,该方法部分逻辑如下。
# apscheduler/scheduleers/base.py/BaseScheduler
with self._jobstores_lock:
# Create a default job store if nothing else is configured
if 'default' not in self._jobstores:
self.add_jobstore(self._create_default_jobstore(), 'default')
其调用了_create_default_jobstore
方法创建默认jobstore,该方法代码如下。
# apscheduler/scheduleers/base.py/BaseScheduler
def _create_default_jobstore(self):
"""Creates a default job store, specific to the particular scheduler type."""
return<