That’s par for the course in Python- everyone seems to have their own pattern.
Note: Skip ahead to “Set and forget…” if you don’t need to stop or interact with your long running task
In my case I use a pattern called StoppableThread
and another called AsyncWorker
which, when combined, give you nice copy and paste classes to handle most of the common use cases for threads- at least until it starts getting very application specific and complex.
They are as follows:
import threading
class StoppableThread(threading.Thread):
"""Basic Stoppable Thread Wrapper
Adds event for stopping the execution
loop and exiting cleanly."""
def __init__(self):
threading.Thread.__init__(self)
self.stop_event = threading.Event()
self.daemon = True
def start(self):
if not self.isAlive():
self.stop_event.clear()
threading.Thread.start(self)
def stop(self):
if self.isAlive():
self.stop_event.set()
self.join()
class AsyncWorker(StoppableThread):
"""Basic thread wrapper class for asynchronously running functions
Return False from the worker function to abort loop."""
def __init__(self, todo):
StoppableThread.__init__(self)
self.todo = todo
def run(self):
while not self.stop_event.is_set():
# Explicitly check for False being returned
# from worker, IE: Don't allow None
if self.todo() is False:
self.stop_event.set()
break
In your case you might want to rewrite your 5 minute loop to be run by AsyncWorker
, which basically involves converting your loop
into function
which can be run over and over again. This is by no means essential, but it does mean - assuming what you’re doing allows - that you can stop this process before the 5 minute run time is up.
A simple example might be:
count = 0
def count_to_ten():
global count
count += 1
if count == 10:
return False
time.sleep(1)
worker = AyncWorker(count_to_ten)
worker.start()
while True:
print(count)
time.sleep(0.5)
Technically the AsyncWorker
code should probably use while not event.wait(some_sleep_amount)
to delay, rather than time.sleep()
but this is a minor implementation detail you’ll only run into with more sophisticated uses of threads.
Set and forget…
If you dont want or need to stop your 5 minute task mid process, and if your task is sufficiently detacted from the rest of your code that you’re really just runnign something in the background, you can just spawn a thread and forget about it like so:
import threading
import time
def long_running_task():
for x in range(100):
time.sleep(10)
thread = threading.Thread(target=long_running_task)
thread.start()
In all cases your “thread” should have some kind of time.sleep()
becuase Python has a “global interpreter lock” that basically only allows one thread to access objects at a time. If you don’t give up the “GIL” manually to give other code a chance to run and interact with the objects it needs, you’ll run into all sorts of exciting problems!