当前位置 博文首页 > python单线程实现多个定时器示例

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

    作者:admin 时间:2021-07-03 18:44

    单线程实现多个定时器

    NewTimer.py

    复制代码 代码如下:

    #!/usr/bin/env python

    from 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 < 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()

    jsjbwy
    下一篇:没有了