PYTHON 定时器简单封装,基于SCHED

时间:2023-11-30 23:05:08

python fresher,轻拍。

在写后台服务时经常会遇到很多定时器的场景,threading.Timer类每实例化一个定时器会有一个新线程去执行,在客户端使用倒是没有问题,如果是服务器端定时器数量多了会影响性能。通常的做法是一个线程按照指定精度发出Ticker,然后检查有没有设置定时器,由则触发;同时要提供SetTimer,KillTimer方法。常用的算法有基于小根堆,时间轮。

本例采用py内置模块sched调度器,sched模块内部使用的优先级队列管理任务,性能未测。

#!/usr/bin/env python3
#-*- coding: utf-8 -*- import sched
import time
import threading '''
定时器类,基于sched调度,独立线程服务
'''
class Timer(threading.Thread):
'''初始化'''
def __init__(self,interval=0.05):
threading.Thread.__init__(self)
self.__sch = sched.scheduler(time.time,time.sleep)
self.__flag = True
self.__min_interval = interval #overload
def run(self):
while self.__flag:
self.__sch.run()
time.sleep(self.__min_interval)
continue #overload
def Start(self):
self.start() def SetTimer(self,interval,func,args):
return self.__sch.enter(interval,0,func,args) def KillTimer(self,event):
try:
self.__sch.cancel(event)
except ValueError as e:
print("KillTimer err:",e)
else:
print("KillTimer unknow err") def Destroy(self):
self.__flag=False if __name__ == "__main__":
t=Timer()
t.Start() def func(msg):
print("timeout ", msg) e=t.SetTimer(1,func,("msg",))
print("set timer",e)
#t.KillTimer(e)
t.Destroy()

已知问题:定时器由单线程执行并触发执行,定时器函数的执行会由很大影响。

if __name__ == "__main__":
t=Timer()
t.Start()
def func(msg):
print("timeout ", msg," now ",time.time())
time.sleep(2) e = t.SetTimer(1, func, ("msg1",))
e = t.SetTimer(1, func, ("msg2",))

执行结果:

timeout  msg1  now  1513819586.3577309
timeout msg2 now 1513819588.3586824

func与定时器是同一线程执行,如果新开线程执行func对于耗时少的func又不划算;这点就体现出golang的优势,定时器触发后直接go func(msg),系统开销很小。