读书人

Python定时器的一个兑现

发布时间: 2012-10-18 13:46:55 作者: rapoo

Python定时器的一个实现
'''
Created on 2012-10-11

@author: blh
'''

import threading
import time

class PyTimer:
PRECISION = 10 # 10ms

def __init__(self, scheduler_num=1):
self.lock = threading.Lock()
self.schedulers = []
self.scheduler_index = 0
self.scheduler_num = scheduler_num

def get_scheduler(self):
self.lock.acquire()
index = self.scheduler_index
self.scheduler_index = (self.scheduler_index + 1) % self.scheduler_num
self.lock.release()
return self.schedulers[index]

def create(self, callback):
return self.Timer(self, callback)

def start(self):
n = 0
while n < self.scheduler_num:
scheduler = self.Scheduler(n)
scheduler.start()
self.schedulers.append(scheduler)
n += 1

def stop(self):
for scheduler in self.schedulers:
scheduler.stop()

def get_info(self):
info = ''
total = 0
n = 1
for scheduler in self.schedulers:
count = scheduler.get_count()
info += 'timer-{0}: {1}\n'.format(n, count)
total += count
n += 1
info += 'timer total: {0}\n'.format(total)
return info

class Timer:
def __init__(self, manager, callback):
self.manager = manager
self.callback = callback
self.scheduler = None
self.timeout = True

#intval unit is ms
def set(self, intval):
self.intval = int(intval / PyTimer.PRECISION)
self.scheduler = self.manager.get_scheduler()
self.scheduler.set(self)

def cancel(self):
if self.scheduler:
self.scheduler.cancel(self)

def reset(self, intval):
self.cancel()
self.set(intval)

class Scheduler(threading.Thread):
QUEUE_NUM = 300

def __init__(self, scheduler_id):
threading.Thread.__init__(self)
self.scheduler_id = scheduler_id
self.lock = threading.Lock()
self.queues = {}
self.timers = {}
self.current = 0
self.running = True
for n in range(self.QUEUE_NUM):
self.queues[n] = []

def get_offset(self, intval):
offset = intval
if offset >= self.QUEUE_NUM:
offset = (self.QUEUE_NUM - 1)
return offset

def get_queue(self, offset):
qid = (self.current + offset) % self.QUEUE_NUM
return self.queues[qid]

def enqueue(self, timer):
offset = self.get_offset(timer.intval)
timer.intval -= offset
queue = self.get_queue(offset)
self.timers[timer] = queue
queue.append(timer)

def dequeue(self, timer):
if self.timers.has_key(timer):
queue = self.timers.pop(timer)
queue.remove(timer)

def set(self, timer):
assert(timer)
self.lock.acquire()
self.enqueue(timer)
self.lock.release()
return timer

def cancel(self, timer):
self.lock.acquire()
self.dequeue(timer)
self.lock.release()

def stop(self):
self.running = False

def run(self):
base_time = float(PyTimer.PRECISION) / 1000
sleep_time = base_time
while self.running:
if sleep_time > 0.0:
time.sleep(sleep_time)
t1 = time.time()
self.lock.acquire()
queue = self.queues[self.current]
while len(queue):
timer = queue.pop()
if timer.intval:
self.enqueue(timer)
else:
self.timeout(timer)
self.current = (self.current + 1) % self.QUEUE_NUM
self.lock.release()
t2 = time.time()
sleep_time = base_time - (t2 - t1)

def timeout(self, timer):
self.timers.pop(timer)
self.lock.release()
timer.callback()
self.lock.acquire()

def get_count(self):
self.lock.acquire()
count = len(self.timers)
self.lock.release()
return count

class TimerDemo:
def __init__(self):
self.timer = PyTimer()
self.timer.start()

def test(self):
self.t1 = self.timer.create(self.timeout1s)
self.t1.set(1000)
self.t2 = self.timer.create(self.timeout3s)
self.t2.set(3000)
self.t3 = self.timer.create(self.timeout600ms)
self.t3.set(600)


def timeout1s(self):
print 'timeout1s'
self.t1.set(1000)

def timeout3s(self):
print 'timeout3s'
self.t2.set(3000)

def timeout600ms(self):
print 'timeout600ms'
self.t3.set(600)


if __name__ == '__main__':
demo = TimerDemo()
demo.test()


读书人网 >perl python

热点推荐