python单线程实现多个定时器示例

单线程实现多个定时器

newtimer.py

代码如下:

#!/usr/bin/env python

from heapq import *from threading import timerimport threadingimport uuidimport timeimport datetimeimport sysimport math

global timerstampglobal timertimesclass cancelfail(exception): pass

class slot(object): def __init__(self, period=0, interval=1, function=none, args=[], kwargs={}): self.period = period self.pc = 0 self.interval = interval self.fire = 0 self.id = uuid.uuid1() self.function = function self.args = args self.kwargs = kwargs#system resolution millisecond class newtimer(object): #set enough time make thread sleep, when newtimer empty set enoug time, too #make sure sum of your timer call back function execute time shorter than resolution #todo use a worker thread to operate timer call back function def __init__(self, resolution=1000): global timerstamp timerstamp = int(time.time() * 1000) self.nofire = sys.maxint #next fire time interval self.firestamp = self.nofire + timerstamp self.resolution = resolution# 1s self.lock = threading.rlock() self.wait = dict() self.ready = dict()

self._start()

“”” private operate ready list “”” def _addtoreadylist(self, slot, firestamp): box = dict( [ (slot.id, slot)]) if not self.ready.has_key( firestamp ): self.ready.update( [(firestamp, box)] ) else: boxs = self.ready.get(firestamp) boxs.update( box ) def _delfromreadylist(self, slot): boxs = self.ready.get(slot.fire) try: box = boxs.pop(slot.id) if not boxs: self.ready.pop(slot.fire) except (attributeerror, keyerror): raise cancelfail “”” inside “”” def _start(self): global timerstamp try: self.firestamp = sorted( self.ready.keys() )[0] stamp = float((timerstamp + self.firestamp – int(time.time()*1000)))/1000 except indexerror: self.firestamp = self.nofire stamp = self.nofire try: self.timer.cancel() except attributeerror: pass self.timer = timer( stamp, self.hander) self.timer.start() def hander(self, *args, **kwargs): “”” find time arrive slot, do it function “”” self.lock.acquire() try: boxs = self.ready.pop( self.firestamp ) slots = boxs.values() except keyerror: slots = [] for slot in slots: if slot.period: slot.pc += 1 if slot.pc != slot.period: slot.fire = slot.interval + slot.fire self._addtoreadylist(slot, slot.fire) elif slot.period == -1: slot.fire = slot.interval + slot.fire self._addtoreadylist(slot, slot.fire) “”” “”” self._start() self.lock.release()

for slot in slots: try: slot.function(slot.args, slot.kwargs) except exception: print “slot id %s, timer function fail” % slot.id “”” operate new timer manager itself “”” def stop(self): self.timer.cancel() “”” new timer manager “”” def add(self, period=0, interval=1, function=none, args=[], kwargs={}): “”” period: one time = 0, times = >0, always = -1 interval: timer fire relative timerreference function: when timer fire, call back function args,kwargs: callback function args “”” interval = int(interval) * self.resolution#seconds if interval < self.resolution: interval = self.resolution slot = slot( period, interval, function, *args, **kwargs ) box = dict([(slot.id, slot)]) self.wait.update(box) return slot def remove(self, slot): if isinstance(slot, slot): self.cancel(slot) try: self.wait.pop(slot.id) except keyerror: print "wait dict not has the cancel timer" """ timer api """ def reset(self, slot): if isinstance(slot, slot): self.cancel(slot) slot.pc = 0 self.start(slot) def start(self, slot): def newtimerstamp(timebase, resolution): nowoffset = int(time.time() * 1000) - timebase if nowoffset % resolution < resolution / 10: currentstamp = nowoffset / resolution else: currentstamp = (nowoffset + resolution - 1) / resolution return currentstamp * 1000 global timerstamp if isinstance(slot, slot): firestamp = slot.interval + newtimerstamp(timerstamp, self.resolution) slot.fire = firestamp self.lock.acquire() self._addtoreadylist(slot, firestamp) if self.firestamp > slot.fire: self._start() self.lock.release() def cancel(self, slot): if isinstance(slot, slot): try: self.lock.acquire() self._delfromreadylist(slot) self._start() self.lock.release() except cancelfail: self.lock.release()def hello( *args, **kargs): print args[0], datetime.datetime.now()if __name__ == “__main__”: print “start test timer”, datetime.datetime.now() nt = newtimer(500) t0 = nt.add( -1, 5, hello, [0]) t1 = nt.add( 4, 7, hello, [1]) t2 = nt.add( 1, 3, hello, [2])# t3 = nt.add( 1, 4, hello, [3])# t4 = nt.add( 4, 5, hello, [4]) t5 = nt.add( 12, 5, hello, [5])# t6 = nt.add( 9, 7, hello, [6]) t7 = nt.add( 1, 8, hello, [7])# t8 = nt.add( 40, 1, hello, [8]) nt.start( t0 ) nt.start( t1 ) nt.start( t2 )# nt.start( t3 )# nt.start( t4 ) nt.start( t5 )# nt.start( t6 ) nt.start( t7 )# nt.start( t8 )

nt.cancel(t2) nt.cancel(t3) nt.remove(t5) nt.remove(t3) time.sleep(3) nt.start(t2) nt.cancel(t8) time.sleep(300) nt.stop() print “finish test timer”, datetime.datetime.now()