资讯专栏INFORMATION COLUMN

python从写循环定时器学习Timer

lemon / 2017人阅读

摘要:更循环定时器这里有更的方法重点研究类,它继承了,但是重写了父类的方法。再看看类中的语句,直到才会退出循环,定时器才结束。我们知道定时器有一个方法可以提前取消操作。这样便完成了一个还不错的循环定时器。

python 如何写一个定时器,循环定时做某一操作呢?

Timer 对象
from threading import Timer
def hello(): 
    print "hello, world" 
   
t = Timer(10.0, hello) 
t.start()

10秒后输出:

hello, world

重点研究 t = Timer(10.0, hello) 这句代码,python 提供了一个Timer 对象,它会在指定的时间后执行某一操作;它的完整形式:

class threading.Timer(interval, function, args=[], kwargs={})

interval 是时间间隔,function 是可调用的对象,argskwargs 会作为 function 的参数。

注意:这里只会执行一次 function,而不会一直定时执行,且 Timer 在执行操作的时候会创建一个新的线程。

Timer 在 python2 和 python3 有点区别:

# python2.7
def Timer(*args, **kwargs):
    return _Timer(*args, **kwargs)
# python3.7
class Timer(Thread):
    pass

在 python3,TimerThread 的子类;在 python2,_TimerThread 的子类,而 Timer 只是 _Timer 类的工厂方法。

上面的代码只会打印一次 hello, world 后退出,那么如何循环间隔打印呢?

粗陋的循环定时器

一种方法是在 function 里继续注册一个 Timer,这样就可以在下一个 interval 继续执行 function

from threading import Timer
def hello(): 
    print "hello, world" 
    Timer(10.0, hello) .start()

t = Timer(10.0, hello) 
t.start()

每隔 10 秒输出一个 hello, world

达到效果了,但是这里面好像有点问题。回到 Timer 本身,它是一个 thread,每次循环间隔操作,系统都要创建一个线程,然后再回收,这对系统来说开销很大。如果时间间隔 interval 很短,系统会一下子创建很多线程,这些线程很难快速回收,导致系统内存和cpu资源被消耗掉。
所以不提倡在 function 里继续注册一个 Timer。

更 pythonic 循环定时器

这里有更 pythonic 的方法:

from threading import _Timer
def hello():
     print "hello, world"
class RepeatingTimer(_Timer): 
    def run(self):
        while not self.finished.is_set():
            self.function(*self.args, **self.kwargs)
            self.finished.wait(self.interval)
t = RepeatingTimer(10.0, hello)
t.start()

重点研究 RepeatingTimer 类,它继承了 threading._Timer,但是重写了父类的 run 方法。这是 Python2 的写法,python3 中 RepeatingTimer 应该继承 threading.Timer

为什么要重写 Threadrun 方法?

_Timer 是一个 Thread 子类,我们先看看 Thread 类的 run 用法。

from threading import Thread
def hello():
     print "hello, world"
# 继承 Thread
class MyThread(Thread):
    # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
    def run(self):
        hello()
t = MyThread()
t.start()

Thread 对象的完整定义:

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})

其中 run 方法代码:

class Thread(_Verbose):
    def run(self):
        try:
            if self.__target:
                self.__target(*self.__args, **self.__kwargs)
        finally:
            # Avoid a refcycle if the thread is running a function with
            # an argument that has a member that points to the thread.
            del self.__target, self.__args, self.__kwargs

标准的 run 方法用于执行用户传入构造函数的 target 方法。 子类可以重写 run 方法,把要执行的代码写到 run 里面,线程在创建后,用户调用 start() 方法会运行 run() 方法。

所以 RepeatingTimer 重写 _Timer 的 run() 方法,可以改变线程的执行体,当我们调用 RepeatingTimer 的 start() 方法时会执行我们重写的 run() 方法。

再看看 RepeatingTimer 类中的 while not self.finished.is_set() 语句,self.finished.is_set() 直到 True 才会退出循环,定时器才结束。finishedthreading.Event 对象。一个 Event 对象管理着一个 flag 标志,它能被 set() 方法设置为 True,也能被 clear() 方法设置为 False,调用 wait([timeout]) 线程会一直 sleep 到 flag 为 True 或超时时间到达。

我们知道定时器有一个 cancel() 方法可以提前取消操作。它其实是调用 Event.clear() 方法提前让 wait 方法结束等待,并且判断在 flag 为 true 的情况下不执行定时器操作。具体的代码:

class _Timer(Thread):
    """Call a function after a specified number of seconds:
            t = Timer(30.0, f, args=[], kwargs={})
            t.start()
            t.cancel() # stop the timer"s action if it"s still waiting
    """

    def __init__(self, interval, function, args=[], kwargs={}):
        Thread.__init__(self)
        self.interval = interval
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.finished = Event()

    def cancel(self):
        """Stop the timer if it hasn"t finished yet"""
        self.finished.set()

    def run(self):
        self.finished.wait(self.interval)
        if not self.finished.is_set():
            self.function(*self.args, **self.kwargs)
        self.finished.set()

所以 RepeatingTimer 的 run 方法会一直执行 while 循环体,在循环体了会执行用户传入的 function 对象,并等待指定的时间。当用户想退出定时器时,只需要调用 cancel 方法,将 flag 置为 True 便不会继续执行循环体了。这样便完成了一个还不错的循环定时器。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43373.html

相关文章

  • Python算法引入

    摘要:参数是要测试的代码语句参数是运行代码时需要的设置参数是一个定时器函数,与平台有关。类中测试语句执行速度的对象方法。参数是测试代码时的测试次数,默认为次。方法返回执行代码的平均耗时,一个类型的秒数。 [TOC] 这里主要是算法的介绍以及一些判断算法好坏的标准和方式 引入 如果a+b+c = 1000,且a^2 + b^2 = c^2,如何求出所有a,b,c可能的组合? 第一次尝试: im...

    Godtoy 评论0 收藏0
  • Python中的上下文管理器和else块

    摘要:上下文管理器协议包含和两个方法。因此必要时在上下文管理器函数中使用语句防范错误。构建临时忽略指定异常的上下文管理器。这是个基类,用于定义基于类的上下文管理器。块结束时,按照后进先出的顺序调用栈中各个上下文管理器的方法。 导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握if语句之外的el...

    Michael_Lin 评论0 收藏0
  • 浏览器和Node中的事件循环机制

    摘要:二浏览器端在讲解事件循环之前先谈谈中同步代码异步代码的执行流程。三端我自己认为的事件循环和浏览器端还是有点区别的,它的事件循环依靠引擎。四总结本篇主要介绍了浏览器和对于事件循环机制实现,由于能力水平有限,其中可能有误之处欢迎指出。 一、前言 前几天听公司一个公司三年的前端说今天又学到了一个知识点-微任务、宏任务,我问他这是什么东西,由于在吃饭他浅浅的说了下,当时没太理解就私下学习整理一...

    KevinYan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<