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。