ホームページ >バックエンド開発 >Python チュートリアル >複数のタイマーの Python シングルスレッド実装の例

複数のタイマーの Python シングルスレッド実装の例

WBOY
WBOYオリジナル
2016-06-16 08:44:401496ブラウズ

单线程实现多个定时器

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

スロット内のスロットの場合:
try:
slot.function(slot.args, slot.kwargs)
例外を除く:
print "スロット ID %s、タイマー機能が失敗しました" % スロット.id

""" 新しいタイマー マネージャー自体を操作します """
def stop(self):
self.timer.cancel()

""" 新しいタイマー マネージャー"""
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 "テスト終了タイマー", datetime.datetime.now()

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。