I want to make a small function that does some fetching in the background for my application, so I want my application to continue normal execution after calling this (so this should be non-blocking). I want this to run on a scheduled thread every X seconds. To do so I have the following:
def start(self):
sync_thread = threading.Timer(30, self.readMessages(self.queue, self.client))
sync_thread.start()
where queue and client are initialized in the __init__ function and assigned to self.
The first start for the thread and invocation to my readMessages function works well, though currently after 30 seconds I get the following error:
Exception in thread Thread-4:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/threading.py", line 932, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.8/threading.py", line 1254, in run
self.function(*self.args, **self.kwargs)
TypeError: 'NoneType' object is not callable
Any idea what to do with it, or is there a better way to do this?
CodePudding user response:
You are getting the TypeError: 'NoneType' object is not callable because the threading.Timer routine is trying to call the function you passed, however, as @CherryDT mentionned in the comments, you didn't pass any function, rather you passed the return value of the readMessage method in your class.
What you need to do instead is:
def MinPrinter:
def __init__(self, xs):
self.xs = xs
def callback(self, xs): # This is your 'readMessages' function
print(min(xs))
def start(self, n):
t = threading.Timer(n, self.callback, args=(self.xs,))
t.start()
mp = MinPrinter([1, 2, 0, 3, -1])
mp.start(30)
# Will print after 30 seconds
-1
Arguments need to be specified with the args parameter. Optionnaly, you can also pass keyword arguments using the kwargs parameter (need to pass a dictionnary).
CodePudding user response:
try
def start(self):
sync_thread = threading.Timer(30, self.readMessages, args=(self.queue,
self.client))
sync_thread.start()
you should pass a callable object to timer and when you use self.readMessages(self.queue, self.client) you are executing the function and not passing it.
and anyway using Timer will not give you what you want. it will call the function self.readMessages once after 30 seconds but it will not repeat every 30 seconds.
a (very) simple way of doing it
from threading import Thread
from sched import scheduler
import time
class SchedTask(Thread):
def __init__(self, interval, task, task_args=()):
super().__init__()
self.scd = scheduler(time.time, time.sleep)
self.interval = interval
self.task = task
self.task_args = task_args
def schedual_task(self):
self.scd.enter(self.interval, 1, self.schedual_task)
self.task(self.task_args)
self.scd.run()
def run(self):
self.schedual_task()
Then in you code you can use it like that
def t(*args):
print("i am a task")
st = SchedTask(5,t)
st.start()
#rest of your code
...
there are many ways of doing this but this is just a simple example.
