想用pyqt5写一个定时更新svn的软件,定时更新部分用到了apscheduler定时器,但是在写的过程中发现有很多的坑,这里简单的做一个记录。
这是软件的主界面,还未做界面美化,大致功能如图所示。
调度器分为六种,这里主要使用BlockingScheduler和BackgroundScheduler两种。
BlockingScheduler:适用于调度程序是进程中唯一运行的进程,调用start函数会阻塞当前线程,不能立即返回。
BackgroundScheduler:适用于调度程序在应用程序的后台运行,调用start后主线程不会阻塞。
在这里踩到第一个坑,使用BlockingScheduler调度器时候,会阻塞当前线程,pyqt5已经是一个线程,所以在pyqt5中使用调度器会被阻塞,直接崩掉。
def svn_up(self):
scheduler = BackgroundScheduler()
i = 0
week2idx = {'周一': 1, '周二': 2, '周三': 3, '周四': 4, '周五': 5, '周六': 6, '周日': 7}
def job():
os.system('cd ' + dir_path + ' && svn up ' + dir_path)
while i < self.index:
dir_path = self.table.item(i, 2).text()
week = week2idx.get(self.table.item(i, 0).text())
time = self.table.item(i, 1).text()
scheduler.add_job(job, 'cron', day_of_week=week, hour=time.split(':')[0],
minute=time.split(':')[1])
i += 1
scheduler.start()
这里使用while循环,给scheduler添加多个job,但后续会有功能,对添加的job做删除,所以在添加定时任务的时候有两种方法:
1、
scher= scheduler.add_job(job, 'cron', day_of_week=week, hour=time.split(':')[0],minute=time.split(':')[1])
scher.remove()
将add_job实例化出来的对象直接进行remove。
2、
scheduler.add_job(job, 'cron', day_of_week=week, hour=time.split(':')[0],minute=time.split(':')[1],id='job_'+str(self.index-1))
scheduler.remove_job("job_" + str(btn_idx))
添加job时候给job一个id,这里的id需要用字符串,所以对数字进行str处理。
接下来就是遇到的第二个坑,虽然不是很难的问题,但是一直没找对思路,所以还是浪费了很多时间,这里做一下走弯路的经验教训。
def svn_up(self): scheduler = BackgroundScheduler() i = 0 week2idx = {'周一': 1, '周二': 2, '周三': 3, '周四': 4, '周五': 5, '周六': 6, '周日': 7} ```
一开始,实例化scheduler,所以在scheduler.start(),即调度器启动后,因为使用了BackgroundScheduler类型调度器,所以job任务列表就已经进入后台运行,此时再次走进svn_up()函数,再次scheduler
= BackgroundScheduler()实例化一个调度器,想要通过之前添加任务的job_id去删除任务,会报错,找不到job_id。因为此时的scheduler
已经不是第一次启动的scheduler ,而是再次实例化的新scheduler ,即使两个scheduler
同名,也无法找到另一个scheduler 里的的任务。解决方法是svn_up()函数中不要初始化scheduler ,将scheduler
初始化放入整个程序init部分。
> def __init__(self, parent=None):
super(auto_svnup, self).__init__(parent)
self.index = 0
self.initUI()
self.datatime_time = '00:00:00'
self.datatime_week = '周一'
self.scheduler = BackgroundScheduler()