这段代码实现了一个简单的任务调度器,用于在指定的时间执行特定任务。以下是对这段代码的详细解释:
代码导入部分
import threading
: 导入 Python 的threading
模块,允许在单独的线程中运行任务调度器,从而不阻塞主线程的执行。from apscheduler.schedulers.blocking import BlockingScheduler
: 从APScheduler
库中导入BlockingScheduler
类。BlockingScheduler
是一个阻塞的调度器,适用于在主线程中运行任务调度。from datetime import datetime
: 导入datetime
模块,用于获取当前的日期和时间,以便在任务执行时打印日志信息。
TaskScheduler
类
-
__init__
方法:- 创建一个
BlockingScheduler
实例,并将其赋值给self.scheduler
。这个调度器将用于管理和调度任务。
- 创建一个
-
add_daily_task
方法:- 定义一个每天在指定时间运行的任务。
- 使用
cron
触发器设置任务的执行时间(小时、分钟、秒)。 add_job
方法用于添加任务到调度器中,func
为要执行的任务函数,id
是任务的唯一标识符,args
是传递给任务函数的参数。
-
add_cron_task
方法:- 定义一个基于 cron 表达式的任务。
- 解析输入的 cron 表达式(格式为 “分钟 小时 日期 月份 星期几”),并验证其包含五个字段。
- 使用
cron
触发器设置任务的执行时间,类似于add_daily_task
。
-
start
方法:- 启动调度器,开始执行已调度的任务。
- 使用
try-except
块捕获KeyboardInterrupt
和SystemExit
异常,以便在用户中断或系统退出时安全地停止调度器。
task_register
函数
-
参数
bot
: 接受一个代表机器人实例的参数(在这里是一个字符串)。 -
内部函数
trigger_report_command
:- 定义了一个简单的任务函数,用于模拟任务的执行。
- 打印当前时间以及任务执行的详细信息(包括模块名称、聊天 ID 和机器人实例)。
-
创建
TaskScheduler
实例:- 初始化一个调度器实例,并添加日常任务和基于 cron 的任务。
-
添加任务:
- 每天4:00 AM执行的任务: 使用
add_daily_task
方法添加。 - 每天9:10 AM执行的任务: 使用
add_cron_task
方法添加,采用 cron 表达式。
- 每天4:00 AM执行的任务: 使用
-
启动调度器线程:
- 创建一个新线程来运行调度器,以避免阻塞主线程。
- 线程中调用
scheduler.start()
方法。
主程序逻辑
-
task_register("example_bot_instance")
:- 调用
task_register
函数,用一个示例的机器人实例启动调度器。
- 调用
-
打印信息:
- 在主线程中打印一条信息,表示调度器在后台运行,主线程可以继续执行其他任务。
这个代码示例展示了如何使用 APScheduler
库来定期执行任务,并通过多线程确保调度器在后台运行,从而不影响其他代码的执行。
完整代码
import threading
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
class TaskScheduler:
def __init__(self):
# 创建一个阻塞调度器实例
self.scheduler = BlockingScheduler()
def add_daily_task(self, task_func, task_name, hour=0, minute=0, second=0, *args):
"""添加一个每天在特定时间运行的任务"""
self.scheduler.add_job(
func=task_func, # 要执行的任务函数
trigger='cron', # 使用cron触发器
hour=hour, # 设置小时
minute=minute, # 设置分钟
second=second, # 设置秒
id=task_name, # 任务名称
args=args # 传递给任务函数的参数
)
def add_cron_task(self, task_func, task_name, cron_expression, *args):
"""使用cron表达式添加一个任务"""
fields = cron_expression.split()
if len(fields) != 5:
raise ValueError("Cron表达式必须包含5个字段(分钟、小时、日期、月份、星期几)")
self.scheduler.add_job(
func=task_func, # 要执行的任务函数
trigger='cron', # 使用cron触发器
minute=fields[0], # cron表达式中的分钟字段
hour=fields[1], # cron表达式中的小时字段
day=fields[2], # cron表达式中的日期字段
month=fields[3], # cron表达式中的月份字段
day_of_week=fields[4], # cron表达式中的星期几字段
id=task_name, # 任务名称
args=args # 传递给任务函数的参数
)
def start(self):
"""启动调度器"""
try:
print("启动调度器...")
self.scheduler.start()
except (KeyboardInterrupt, SystemExit):
print("调度器已停止。")
def task_register(bot):
chat_id = "example_chat_id"
def trigger_report_command(bot, chat_id, module):
# 打印执行任务的详细信息
print(f"[{datetime.now()}] 执行{module}报告,聊天ID: {chat_id},机器人: {bot}")
scheduler = TaskScheduler()
# 每天4:00 AM执行的任务
scheduler.add_daily_task(
trigger_report_command,
"日报 04:00 AM",
4,
0,
0,
bot,
chat_id,
"市场"
)
# 使用cron表达式每天9:10 AM执行的任务
scheduler.add_cron_task(
trigger_report_command,
"Cron报告 09:10 AM",
"10 9 * * *",
bot,
chat_id,
"市场"
)
# 在一个单独的线程中启动调度器
scheduler_thread = threading.Thread(target=scheduler.start)
scheduler_thread.start()
# 示例调用
task_register("example_bot_instance")
# 继续执行其他代码
print("调度器正在后台运行。")