Python定时器的一个实现

本文介绍了一个基于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()
   

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>我们正在回答用户关于Python实现定时器的方法的问题。根据用户提供的引用资料,我们可以总结出以下几种方法: 1. 使用threading.Timer:这是threading模块提供的定时器,可以在指定时间后执行一个函数,也可以循环执行。 2. 使用schedule库:一个轻量级的定时任务调度库,可以按照设定的时间规则执行任务。 3. 在异步编程中使用定时器:例如在asyncio中使用异步定时任务。 4. 使用time.sleep结合循环:通过循环和休眠实现定时任务,但这种方法可能会阻塞线程。 5. 自定义定时器类:通过结合threading.Timer和循环控制,实现可重复执行的定时器。 6. 使用Twisted框架:这是一个事件驱动的网络引擎,也提供了定时任务的功能。 由于引用中提供了多种方法,我们将挑选几种常见且实用的方法进行详细介绍,并给出示例代码。同时,我们会参考引用中的代码片段,但会确保代码正确性和可读性。 注意:用户要求使用中文回答,并且按照系统级指令,数学表达式使用$...$,但本问题不涉及数学表达式,所以主要关注代码格式和引用标识。 我们将按照以下结构回答: 1. 简单介绍Python实现定时器的几种主要方法。 2. 每种方法的详细说明和示例代码(代码块使用```python标记)。 3. 在回答末尾生成相关问题。 注意引用标识:在引用相关内容的末尾添加引用标识,如[^1]。 开始回答: </think>### Python实现定时器的几种方法 根据引用资料,Python实现定时器主要有以下五种方式,每种方法适用于不同场景: #### 1. threading.Timer基础定时器(单次执行) ```python import threading def task(): print("定时任务执行!") timer = threading.Timer(5.0, task) # 5秒后执行 timer.start() ``` > 优点:简单易用,内置标准库 > 缺点:只能执行单次任务[^1][^2] #### 2. schedule库(循环定时任务) ```python import schedule import time def job(): print("每日定时任务") schedule.every().day.at("03:00").do(job) # 每天3点执行 while True: schedule.run_pending() time.sleep(60) # 每分钟检查一次 ``` > 优点:支持复杂时间规则(cron风格) > 缺点:需要持续运行主线程[^1][^4] #### 3. 自定义循环定时器类(非阻塞) ```python import threading import time class RepeatedTimer: def __init__(self, interval, func): self.timer = None self.interval = interval self.func = func self.is_running = False self.start() def _run(self): self.is_running = False self.start() self.func() def start(self): if not self.is_running: self.timer = threading.Timer(self.interval, self._run) self.timer.start() self.is_running = True def stop(self): self.timer.cancel() self.is_running = False # 使用示例 rt = RepeatedTimer(1, lambda: print("每秒执行")) # 每秒触发 time.sleep(5) rt.stop() ``` > 优点:可复用、非阻塞式执行 > 缺点:需要自行管理生命周期[^5] #### 4. 异步定时器(asyncio) ```python import asyncio async def timed_task(): while True: print("异步定时执行") await asyncio.sleep(3600) # 每小时执行 # 启动方式 asyncio.run(timed_task()) ``` > 优点:适合异步应用,节省资源 > 缺点:需要理解异步编程模型[^1][^2] #### 5. 精确时间点触发(datetime计算) ```python import threading import datetime def execute_at(target_time): now = datetime.datetime.now() delay = (target_time - now).total_seconds() threading.Timer(delay, lambda: print("准时触发")).start() # 明天3点执行 tomorrow_3am = datetime.datetime.now() + datetime.timedelta(days=1) tomorrow_3am = tomorrow_3am.replace(hour=3, minute=0, second=0) execute_at(tomorrow_3am) ``` > 优点:可指定绝对时间点 > 缺点:计算较复杂[^4] --- ### 方法选择建议 | 场景 | 推荐方案 | 关键特性 | |------|----------|---------| | 简单单次延迟 | `threading.Timer` | 零依赖 | | 周期性任务 | `schedule`库 | 语法直观 | | 高精度控制 | 自定义`RepeatedTimer` | 毫秒级精度 | | 异步应用 | `asyncio` | 非阻塞IO | | 绝对时间触发 | `datetime+Timer` | 日历时间触发 | > 注意:长时间运行的定时任务建议结合日志记录和异常处理,避免任务中断[^3][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值