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

yipeiwu_com6年前Python基础

单线程实现多个定时器

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

相关文章

python Django 创建应用过程图示详解

python Django 创建应用过程图示详解

如图输入如下命令 python manage.py startapp apitest 添加应用到 autotest项目项目下 在settings.pyo 中加入“apitest”...

PyQt 图解Qt Designer工具的使用方法

PyQt 图解Qt Designer工具的使用方法

前言 Qt Designer是PyQt程序UI界面的实现工具,Qt Designer工具使用简单,可以通过拖拽和点击完成复杂界面设计,并且设计完成的.ui程序可以转换成.py文件供pyt...

python如何基于redis实现ip代理池

这篇文章主要介绍了python如何基于redis实现ip代理池,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 使用apschedule...

Python实现的一个简单LRU cache

起因:我的同事需要一个固定大小的cache,如果记录在cache中,直接从cache中读取,否则从数据库中读取。python的dict 是一个非常简单的cache,但是由于数据量很大,内...

Python基于更相减损术实现求解最大公约数的方法

Python基于更相减损术实现求解最大公约数的方法

本文实例讲述了Python基于更相减损术实现求解最大公约数的方法。分享给大家供大家参考,具体如下: 先从网上摘录一段算法的描述如下: 更相减损法:也叫 更相减损术,是出自《 九章算术》的...