Reputation: 33
I would like to call a function that checks a value on a bus periodically using the multiprocessing library (non-blocking desired). There is a way to do it using the threading library but it doesn't use multiple processes.
I've seen example code of this kind of functionality using the threading library but I'd like to achieve the same thing using the multiprocessing library. The official documentation for multiprocessing states:
"Note multiprocessing contains no analogues of threading.active_count(), threading.enumerate(), threading.settrace(), threading.setprofile(), threading.Timer"
however, in the examples I've seen for the threading library, they use threading.Timer. Is there a similar function for multiprocessing?
import time, threading
def foo():
print(time.ctime())
threading.Timer(10, foo).start()
foo()
#output:
#Thu Dec 22 14:46:08 2011
#Thu Dec 22 14:46:18 2011
#Thu Dec 22 14:46:28 2011
#Thu Dec 22 14:46:38 2011
Executing periodic actions in Python
The code above is an example for used with the threading library. Also, I was wondering if that was bad practice because the threads are never terminated (.join()).
Upvotes: 1
Views: 1712
Reputation: 1518
To extend Nosvan's answer to have a truly periodic timer (well it drifts by a few milliseconds), you simply can extend the Timer
class like this:
from typing import Callable
class PeriodicTimer(Timer):
def __init__(self, interval: int, function: Callable):
super(PeriodicTimer, self).__init__(interval, function)
def run(self):
while not self.finished_event.is_set():
# function callback could set the stop event
self.function(*self.args, **self.kwargs)
self.finished_event.wait(self.timeout)
and may I suggest to modify the Timer
class to not have mutable arguments in the constructor:
from multiprocessing import Process
from multiprocessing import Event
from typing import Callable
class Timer(Process):
def __init__(self, timeout: int, function: Callable, args=None, kwargs=None):
super(Timer, self).__init__()
self.timeout = timeout
self.function = function
self.args = [] if args is None else args
self.kwargs = {} if kwargs is None else kwargs
self.finished_event = Event()
def cancel(self):
"""Stop the timer if it hasn't finished yet"""
self.finished_event.set()
def run(self):
self.finished_event.wait(self.timeout)
if not self.finished_event.is_set():
self.function(*self.args, **self.kwargs)
self.finished_event.set()
Here is an exhaustive explanation of why to avoid mutable default arguments:
https://web.archive.org/web/20200221224620/http://effbot.org/zone/default-values.htm
Upvotes: 0
Reputation: 151
Basically, there is no timer class in the multiprocessing module. It should be, but seems like that when they migrated from pyprocessing to multiprocessing they didn't include that part. It's explained here https://stackoverflow.com/a/25297863/6598433.
You can make a working timer for the multiprocessing library manually as dano posted in https://stackoverflow.com/a/25297758/6598433
from multiprocessing import Process, Event
class Timer(Process):
def __init__(self, interval, function, args=[], kwargs={}):
super(Timer, self).__init__()
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()
Check here the full question: Why no Timer class in Python's multiprocessing module?
Upvotes: 1