Detailed explanation of Python multithreaded Timer timer and delayed execution and Event events

  • 2021-07-03 00:35:58
  • OfStack

Timer inherits the subclass Thread, is a subclass of Thread, and is also a thread class, with the ability and characteristics of threads. This class is used to define how often to execute a function.

Its instance is a thread that can delay execution of the target function, and can cancel it before actually executing the target function.

Timer source code:


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()

The Timer class uses methods and Thread to define sub-threads, interval pass-in intervals, function pass-in functions executed by threads, and args and kwargs pass-in parameters of functions.

Advance 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===")

Run results:

===end===

After the start method executes, the Timer object waits for 10 seconds and then executes the add function. At the same time, in the waiting phase before executing the add function, the main thread uses the cancel method of the child thread, which skips the end of the execution function.

Implement the Timer timer using the event event:


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()

Run results:

WARNING:root:9

The Event event, which is the simplest implementation of the inter-thread communication mechanism, uses an internal tag flag and operates through True or False changes of flag.

Event source code:

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 method:

• set () flag is set to True
• clear () flag is set to False
Whether is_set () flag is True, returns a Boolean value
• ES 79EN (ES 80EN = ES 81EN) sets the duration of waiting for ES 82EN to change to ES 83EN, and ES 84EN is an infinite wait. When True is returned, False is returned before timeout.

Examples:

The boss hired a worker to make cups, and the boss waited for the worker until he made ten cups.


import threading
import logging
import time
logging.basicConfig(level=logging.INFO)
cups = []
event = threading.Event()#event Object 
def boss(e:threading.Event):
 if e.wait(30):# Maximum wait 30 Seconds 
  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 Set to True
   break
b = threading.Thread(target=boss,name='boos',args=(event,))
w = threading.Thread(target=worker,args=(10,event))
w.start()
b.start()

Run results:

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.

The boss and worker use the token flag of the same Event object.

The boss wait () is set to wait for 30 seconds at most, and wait for flag to change to True. When the worker makes enough 10 cups, set flag to True, and the worker must not make the cups within 30 seconds.

Use of 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) #  You can also use the time.sleep(10)
e.set()
print('Man Exit.')

Run results:

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.

The difference between wait and sleep is that wait will voluntarily give up the time slice, and other threads can be scheduled, while sleep will take up the time slice and not give up.

Summary:

The Timer timer inherits from the Thread class and is also a thread class. Its purpose is to wait for n seconds before executing an objective function, which can be canceled early using cancel.

The Event event maintains an flag flag value through True and False, and decides to do something through this flag value. The wait () method can set the maximum waiting time for flag to be set to Ture, and return False before the timeout is set to True.

PS: Let's look at the timer Timer of python

Class timer

Timer (Timer) is a derived class of Thread that calls a method after a specified time.

Construction method:


Timer(interval, function, args=[], kwargs={}) 
    interval:  The specified time  
    function:  Method to execute  
    args/kwargs:  Parameters of the method 

Instance method:

Timer derives from Thread without adding instance methods.

Example 1:


# encoding: UTF-8
import threading
def func():
  print 'hello timer!'
timer = threading.Timer(5, func)
timer.start()

The thread is delayed for 5 seconds before execution.

Summarize


Related articles: