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.