Python使用threading.Timer实现轻量级定时数据库更新
本文介绍利用Python的threading.Timer模块实现轻量级定时数据库更新的方法。通过计算时间差创建非阻塞线程执行更新操作,避免了传统多进程方案的资源消耗。重点解析了异步环境下必须手动调用commit()确保数据生效的关键细节,并指出了服务重启导致线程丢失的局限性及持久化解决方案。
在需要定期修改数据库的场景中,通常的做法是启动一个独立的定时进程来执行任务。然而,如果将此类定时逻辑封装为业务接口,传统的定时进程方案显得过于笨重。例如,若需执行100次数据库修改,常规方式会启动100个进程,尽管这些进程轻量,但仍存在资源管理的冗余感。实际上,利用threading.Timer创建特定线程来执行数据库修改操作是更优的选择,其核心思路简洁明了。
首先,接收目标更新时间update_time,通过将其与当前系统时间进行减法运算,计算出距离执行操作的时间差time_delay。为了精确计算两个标准时间格式字符串之间的差值,可以使用datetime.datetime.strptime()对时间字符串进行格式化解析。解析后的时间对象可直接相减,对结果调用.seconds()属性即可转换为秒数作为延迟时间。
其次,将数据库修改逻辑封装为update()方法,并将该方法及计算出的时间差传入threading.Timer构造函数以创建线程实例。其标准用法为threading.Timer(interval, function, args=[], kwargs={}),其中interval指定延迟执行的秒数。创建实例后调用start()即可启动线程。需要注意的是,Timer线程是非阻塞的,允许同时创建多个线程而互不干扰。
具体实现代码如下
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from model import Table
from handler.base_handler import BaseHandler
from threading import Timer
import datetime
class TimeHandler(BaseHandler):
def do_action(self):
update_time = "2018-04-07 18:00:00"
ads_id = "test_1"
t_online = datetime.datetime.strptime(update_time, '%Y-%m-%d %H:%M:%S')
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
t_now = datetime.datetime.strptime(now, '%Y-%m-%d %H:%M:%S')
time_delay = (t_online - t_now).seconds
t1 = Timer(time_delay, self.update, (ads_id, ))
t1.start()
self.result = "success"
return
def update(self, ads_id):
self.db.dsp.query(Table).filter(Table.ads_id == ads_id).update({Table.is_del: 0})
self.db.dsp.commit()
可以将update_time设置为前端传入的参数,从而实现在指定时间执行数据库更新。在实际开发中曾遇到一个常见陷阱:数据库修改未生效。经排查,原因是遗漏了最后一行的commit()调用。虽然基类BaseHandler中通常封装了commit逻辑,但在Timer线程中执行的update()属于异步操作,必须在线程内部显式执行commit()才能确保数据变更持久化。
这种基于Timer的定时执行方式相比传统定时进程更加轻量且实现简单,但也存在明显局限。当服务关闭时,所有定时线程会随主进程一同销毁。因此,该方案的前提是服务必须保持稳定运行,不可随意重启。若需支持服务重启,必须设计机制将未完成的定时任务持久化(如写入数据库),并在服务启动时读取这些任务并重新创建对应的定时线程。
以上内容涵盖了利用Python Timer模块进行轻量级定时数据库更新的核心要点,希望能为相关开发工作提供参考与帮助。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













