zoukankan      html  css  js  c++  java
  • [Python 多线程] Timer定时器/延迟执行、Event事件 (七)

    Timer继承子Thread类,是Thread的子类,也是线程类,具有线程的能力和特征。这个类用来定义多久执行一个函数。

    它的实例是能够延迟执行目标函数的线程,在真正执行目标函数之前,都可以cancel它。

    Timer源码:

    class Timer(Thread):
        def __init__(self, interval, function, args=None, kwargs=None):
            Thread.__init__(self)
            self.interval = interval
            self.function = function
            self.args = args if args is not None else []
            self.kwargs = kwargs if kwargs is not None else {}
            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()
    

      Timer类使用方法与Thread定义子线程一样,interval传入间隔时间,function传入线程执行的函数,args和kwargs传入函数的参数。

    提前cancel:

    import threading
    import time
    
    def add(x,y):
        print(x+y)
    
    t = threading.Timer(10,add,args=(4,5))
    t.start()
    
    time.sleep(2)
    t.cancel()
    print("===end===")
    
    运行结果:
    ===end===
    

      start方法执行之后,Timer对象会处于等待状态,等待10秒之后会执行add函数。同时,在执行add函数之前的等待阶段,主线程使用了子线程的cancel方法,就会跳过执行函数结束。

    使用event 事件实现Timer计时器:

    import threading
    import logging
    import time
    logging.basicConfig(level=logging.INFO)
    
    # class MyTimer(threading.Thread):
    class MyTimer:
        def __init__(self,interval,fn,args=None):
            self.interval = interval
            self.fn = fn
            self.args = args
            self.event = threading.Event()
    
        def start(self):
            threading.Thread(target=self.__do).start()
    
        def cancel(self):
            self.event.set()
    
        def __do(self):
            self.event.wait(self.interval)
            if not self.event.is_set():
                self.fn(*self.args)
    
    
    def add(x,y):
        logging.warning(x+y)
    
    
    t = MyTimer(5,add,(4,5))
    t.start()
    
    # time.sleep(2)
    # t.cancel()
    
    运行结果:
    WARNING:root:9
    

      Event事件,是线程间通信机制中最简单的实现,使用一个内部的标记flag,通过flag的True或False的变化来进行操作。

    Event源码:

    class Event:
    
        def __init__(self):
            self._cond = Condition(Lock())
            self._flag = False
    
        def _reset_internal_locks(self):
            self._cond.__init__(Lock())
    
        def is_set(self):
            return self._flag
    
        isSet = is_set
    
        def set(self):
            with self._cond:
                self._flag = True
                self._cond.notify_all()
    
        def clear(self):
            with self._cond:
                self._flag = False
    
        def wait(self, timeout=None):
            with self._cond:
                signaled = self._flag
                if not signaled:
                    signaled = self._cond.wait(timeout)
                return signaled    
    

      Event 方法:

    • set()                    flag设置为True
    • clear()                 flag设置为False
    • is_set()                flag是否为True,返回布尔值
    • wait(timeout=None)  设置等待flag变为True的时长,None为无限等待。等到了返回True,未等到超时了就返回False。

    举例:

    老板雇佣了一个工人,让他生产杯子,老板一直等着工人,直到生产了10个杯子。

    import threading
    import logging
    import time
    logging.basicConfig(level=logging.INFO)
    
    cups = []
    event = threading.Event()#event对象
    
    def boss(e:threading.Event):
        if e.wait(30):#最多等待30秒
            logging.info('Good job.')
    
    def worker(n,e:threading.Event):
        while True:
            time.sleep(0.5)
            cups.append(1)
            logging.info('make 1')
            if len(cups) >=n:
                logging.info('I finished my job. {}'.format(len(cups)))
                e.set()#flag设置为True
                break
    
    b = threading.Thread(target=boss,name='boos',args=(event,))
    w = threading.Thread(target=worker,args=(10,event))
    
    w.start()
    b.start()
    
    运行结果:
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:make 1
    INFO:root:I finished my job. 10
    INFO:root:Good job.
    

      老板和工人使用同一个Event对象的标记flag。

      老板wait()设置为最多等待30秒,等待flag变为True,工人在做够10杯子时,将flag设置为True,工人必须在30秒之内没有做好杯子。

    wait的使用:

    import threading
    import logging
    logging.basicConfig(level=logging.INFO)
    
    def do(event:threading.Event,interval:int):
        while not event.wait(interval): # not event.wait(1) = True
            logging.info('To do sth.')
    
    e = threading.Event()
    t = threading.Thread(target=do,args=(e,1))
    t.start()
    
    e.wait(10) # 也可以使用time.sleep(10)
    e.set()
    print('Man Exit.')
    
    运行结果:
    INFO:root:To do sth.
    INFO:root:To do sth.
    INFO:root:To do sth.
    INFO:root:To do sth.
    INFO:root:To do sth.
    INFO:root:To do sth.
    INFO:root:To do sth.
    INFO:root:To do sth.
    INFO:root:To do sth.
    Man Exit.
    

      wait与sleep的区别是:wait会主动让出时间片,其它线程可以被调度,而sleep会占用时间片不让出。

    小结:

    Timer定时器继承自Thread类,也是线程类。它的作用是等待n秒钟之后执行某个目标函数,可以使用cancel提前取消。

    Event事件是通过True和False维护一个flag标记值,通过这个标记的值来决定做某事,wait()方法可以设置最长等待flag设置为Ture的时长,超时还未设置为True就返回False。

  • 相关阅读:
    验证SMTP工作过程
    FileZilla FTP服务器的安装和配置
    最后一块石头的重量
    不用加号的加法
    同构字符串
    最长公共子序列
    Telnet 验证HTTP工作过程
    矩阵的最小路径和
    子数组的最大累加和问题
    海思开发板——YOLOv3模型移植(4)
  • 原文地址:https://www.cnblogs.com/i-honey/p/8051680.html
Copyright © 2011-2022 走看看