您好,欢迎访问一九零五行业门户网

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

单线程实现多个定时器
newtimer.py
复制代码 代码如下:
#!/usr/bin/env pythonfrom heapq import *
from threading import timer
import threading
import uuid
import time
import datetime
import sys
import math
global timerstamp
global timertimes
class 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             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                 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()
其它类似信息

推荐信息