Periodic Python Threads with on demand trigger - python

I have simple PyGTK app. Since I have to run multiple periodic tasks to fetch some data and refresh GUI, I extended Thread like this:
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.setDaemon(True)
self.event = threading.Event()
self.event.set()
def run(self):
while self.event.is_set():
timer = threading.Timer(60, self._run)
timer.start()
timer.join()
def cancel(self):
self.event.clear()
def _run(self):
gtk.threads_enter()
# do what need to be done, fetch data, update GUI
gtk.threads_leave()
I start threads on app bootstrap, save them in some list and cancel them before exit. This works just perfect.
But now I want to add refresh button which will force one of the threads to run immediately and not wait period of time to be run, if not currently running.
I tried to do that by adding bool var to MyThread to indicate whether a thread is running or not (set before _run, reset on complete), and then just call MyThread._run() if not running, but that causes my app to become unresponsive and _run task to never finish execution.
I'm not sure why this happens. What is the best way to solve this problem? It would be also fine if I can make refresh running in background so it does not block GUI.
Maybe to call run and pass in number of seconds to 1 so timer can trigger it sooner?

Instead of using a Timer, use another Event object in combination with a timeout. You can then set that event from within your button callback. The following code illustrates this (I've stripped your cancelling code to keep it short):
import threading
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.sleep_event = threading.Event()
self.damon = True
def run(self):
while True:
self.sleep_event.clear()
self.sleep_event.wait(60)
threading.Thread(target=self._run).start()
def _run(self):
print "run"
my_thread = MyThread()
my_thread.start()
while True:
raw_input("Hit ENTER to force execution\n")
my_thread.sleep_event.set()
By default "run" will be printed every 60 seconds. If you hit ENTER it will be printed immediately, and then again after 60 seconds, etc.

Related

python schedule library to stop previously running thread when new scheduled thread starts

I have a same thread running every 10 min. but when the new thread starts i want to quit the previous thread so it doesn't keep adding up the space. how can i achieve that. for scheduling of thread.I'm using python schedule library.
this is how I'm scheduling right now
schedule.every(10).minutes.do(sts,threadFunc)
There are two aspects to this question:
identify the currently running job, which is fairly easy.
Kill a running thread in python. There's no great solution for this, and the following code implements the 'stop flag' approach.
I'm solving the first challenge by using a global variable. This variable, named running_thread, holds the currently running thread so that a new job can kill it if needed.
The second challenge requires the running thread to constantly check the status of some flag ('the stop flag'). If the stop flag is set on that thread, it immediately exists.
Here's a code skeleton that demonstrates both these ideas. Jobs take a random amount of time, and I've scheduled them to start every 1 second.
import threading
import time
import schedule
import random
running_thread = None
class StoppableThread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
def __init__(self, *args, **kwargs):
super(StoppableThread, self).__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def job():
current_thread = threading.currentThread()
sleep_time = random.random() * 5
print(f"Starting job, about to sleep {sleep_time} seconds, thread id is {current_thread.ident}")
counter = 0
while counter < sleep_time:
time.sleep(0.1)
counter += 0.1
if current_thread.stopped():
print ("Stopping job")
break
print(f"job with thread id {current_thread.ident} done")
def threadFunc():
global running_thread
if running_thread:
print("Trying to stop thread")
running_thread.stop()
print("Strting thread")
running_thread = StoppableThread(target = job)
running_thread.start()
schedule.every(1).seconds.do(threadFunc)
while True:
schedule.run_pending()
time.sleep(.5)

repeatedly run a function in a new thread

First of all, i'm a python newbie, and i hope you can help me with my problem.
My program (i'm using tkinter) is suppose to check if a process is running, if it's not running, i would like to run it myself.
I want to do run the function that checks the processes every N seconds, I also want my application not to 'freeze' while executing this function, so i decided to use thread, I've made a new class that creates my thread and running my function every interval.
Here's the class:
class TaskThread(threading.Thread):
"""Thread that executes a task every N seconds"""
def __init__(self, interval, callback):
threading.Thread.__init__(self)
self._finished = threading.Event()
self.setInterval(interval)
self.callback = callback
self.run()
def setInterval(self, interval):
"""Set the number of seconds we sleep between executing our task"""
self._interval = interval
def shutdown(self):
"""Stop this thread"""
self._finished.set()
def run(self):
while 1:
if self._finished.isSet(): return
self.callback()
# sleep for interval or until shutdown
self._finished.wait(self._interval)
Here's the function i'm calling from inside the class (a callback function):
def process_running(self):
"check if the process is running"
print("test")
def check_process():
"check if process is alive"
for process in psutil.process_iter():
if self.process_name == process.name():
self.process_id = process.pid
return True
return False
if not check_process():
self.process = subprocess.Popen([self.launcher_exe])
time.sleep(20.0) #let the notepad.exe to load completely
self.process_id = self.process.pid
self.hwnd = self.get_hwnds_for_pid(self.process_id) #get the window handle
and the init of the class is like so :
self.loop = TaskThread(10, self.process_running)
Now, when i'm starting my application, the program is running the check_process function but the application window is not responding, and i can't use the window at all.
I wonder if i did something wrong, hope you can help me.

How do I interrupt or cancel a SimPy Timeout event?

I want to create a timer with a callback that can be interrupted or reset using SimPy. If interrupted, I do not want the callback to be executed, and if reset, I want the timer to restart with the same delay from env.now. This seemed like an easy thing to do initially by simply using env.timeout. However, the documentation notes:
To actually let time pass in a simulation, there is the timeout event. A timeout has two parameters: a delay and an optional value: Timeout(delay, value=None). It triggers itself during its creation and schedules itself at now + delay. Thus, the succeed() and fail() methods cannot be called again and you have to pass the event value to it when you create the timeout.
Because the simulation starts triggered, I can't add callbacks and because you can't call fail, I can't interrupt the timeout.
I've considered just implementing a process that waits one timestep and checks a flag if it's been interrupted or reached the env.now it was waiting for, but this seems horribly inefficient, and if I have a lot of timers (which I will), I'm worried that the number of generators will overwhelm the simulation. (The timeout function seems to work by scheduling itself in the future of the simulation, which is why you can have a ton of those running around).
So the spec is - create an event that triggers a callback after a specified amount of time, but that can be reset or interrupted before that time occurs. Any thoughts?
Well, if I understood your question correctly one thing you can do is create a Timer class with a wait method which checks for simpy.Interrupt. You can imlement stop() so that when it's called, you also call interrupt(). That way the callback will not be executed as long as interrupt() has previously been called. A reset method would simply call stop() (interrupt) and start() again thus setting the action back to running() and calling wait() again, allowing the callback to be executed again after every timeout until interrupt is called again.
Here's an example implementation of such a Timer class:
import simpy
class Timer(object):
def __init__(self, env, delay, callback):
self.env = env
self.delay = delay
self.action = None
self.callback = callback
self.running = False
self.canceled = False
def wait(self):
"""
Calls a callback after time has elapsed.
"""
try:
yield self.env.timeout(self.delay)
self.callback()
self.running = False
except simpy.Interrupt as i:
print "Interrupted!"
self.canceled = True
self.running = False
def start(self):
"""
Starts the timer
"""
if not self.running:
self.running = True
self.action = self.env.process(self.wait())
def stop(self):
"""
Stops the timer
"""
if self.running:
self.action.interrupt()
self.action = None
def reset(self):
"""
Interrupts the current timer and restarts.
"""
self.stop()
self.start()
I know this is an old SO question, but I was looking for a simple SimPy Timer class just like the one provided in #kxirog's answer (which was very useful!), and had a fix for the issue with reset pointed out by #bbengfort. The reset function assumes that interrupt executes immediately, but this is not the case as explained in the SimPy documentation:
What process.interrupt() actually does is scheduling an Interruption event for immediate execution.
So the call to self.start actually executes before the wait process has been interrupted, and that prevented it from starting a new wait process.
Below is a modified version where the reset should work.
import simpy
class Timer(object):
def __init__(self, env, delay, callback):
self.env = env
self.delay = delay
self.action = None
self.callback = callback
def wait(self):
"""
Calls a callback after time has elapsed.
"""
try:
yield self.env.timeout(self.delay)
self.callback()
except simpy.Interrupt:
print("Interrupted!")
def running(self):
"""
Check if timer is running
"""
return self.action is not None and self.action.is_alive
def start(self):
"""
Starts the timer
"""
if not self.running():
self.action = self.env.process(self.wait())
def stop(self):
"""
Stops the timer
"""
if self.running():
self.action.interrupt()
self.action = None
def reset(self):
"""
Interrupts the current timer and restarts.
"""
self.stop()
self.start()

Repeat function at an interval?

I'm making a wxPython app that I need to update a value from the internet every 15 seconds. Is there any way I can have a function to set the value, and make it run in the background at this interval, without interrupting the program?
EDIT: Here's what I'm trying:
import thread
class UpdateThread(Thread):
def __init__(self):
self.stopped = False
UpdateThread.__init__(self)
def run(self):
while not self.stopped:
downloadValue()
time.sleep(15)
def downloadValue():
print x
UpdateThread.__init__()
What you want is to add a thread that runs your task at a specified pace.
You may have a look at this great answer here : https://stackoverflow.com/a/12435256/667433 to help you achieve this.
EDIT : Here is the code that should work for you :
import time
from threading import Thread # This is the right package name
class UpdateThread(Thread):
def __init__(self):
self.stopped = False
Thread.__init__(self) # Call the super construcor (Thread's one)
def run(self):
while not self.stopped:
self.downloadValue()
time.sleep(15)
def downloadValue(self):
print "Hello"
myThread = UpdateThread()
myThread.start()
for i in range(10):
print "MainThread"
time.sleep(2)
Hope it helps
I have made something similar to this:
-you need a thread to run in the background .
-And a define a 'custom' event , so that the tread can notify the UI when needed
Create the custom WX event
(MyEVENT_CHECKSERVER, EVT_MYEVENT_CHECKSERVER) =
wx.lib.newevent.NewEvent()
on UI "init" you can bind the event , and start the thread
# bind the custom event
self.Bind(EVT_MYEVENT_CHECKSERVER, self.foo)
# and start the worker thread
checkServerThread = threading.Thread(target=worker_checkServerStatus
,args=(self,) )
checkServerThread.daemon = True
checkServerThread.start()
the worker thread can be something like this ,ps. caller is the UI instance
def worker_checkServerStatus(caller):
while True:
# check the internet code here
evt = MyEVENT_CHECKSERVER(status='Some internet Status' ) #make a new event
wx.PostEvent(caller, evt) # send the event to the UI
time.sleep(15) #ZZZzz for a bit
Edit: miss read the question...
Another way to do that is with a timer:
import threading
stopNow = 0
def downloadValue():
print("Running downloadValue")
if not stopNow: threading.Timer(15,downloadValue).start()
downloadValue()
This is a classic pattern for repeating a function: the function itself adds a timed call to itself. To start the cycle, call the function (it returns immediately). To break the cycle set stopNow to 1.

Non-blocking class in python (detached Thread)

I'm trying to create a kind of non-blocking class in python, but I'm not sure how.
I'd like a class to be a thread itself, detached from the main thread so other threads can interact with it.
In a little example:
#!/usr/bin/python2.4
import threading
import time
class Sample(threading.Thread):
def __init__(self):
super(Sample, self).__init__()
self.status = 1
self.stop = False
def run(self):
while not(self.stop):
pass
def getStatus(self):
return self.status
def setStatus(self, status):
self.status = status
def test(self):
while self.status != 0:
time.sleep(2)
#main
sample = Sample()
sample.start()
sample.test()
sample.setStatus(0)
sample.stop()
What I'd like is having the "sample" instance running as a separate thread (detached from the main one) so, in the example, when the main thread reaches sample.test(), sample (and only "sample") would go to sleep for 2 seconds. In the meanwhile, the main thread would continue its execution and set sample's status to 0. When after the 2 seconds "sample" wakes up it would see the status=0 and exit the while loop.
The problem is that if I do this, the line sample.setStatus(0) is never reached (creating an infinite loop). I have named the threads, and it turns out that by doing this, test() is run by the main thread.
I guess I don't get the threading in python that well...
Thank you in advance
The object's run() method is what executes in a separate thread. When you call sample.test(), that executes in the main thread, so you get your infinite loop.
Perhaps something like this?
import threading
import time
class Sample(threading.Thread):
def __init__(self):
super(Sample, self).__init__()
self.stop = False
def run(self):
while not(self.stop):
print('hi')
time.sleep(.1)
def test(self):
print('testing...')
time.sleep(2)
#main
sample = Sample()
sample.start() # Initiates second thread which calls sample.run()
sample.test() # Main thread calls sample.test
sample.stop=True # Main thread sets sample.stop
sample.join() # Main thread waits for second thread to finish

Categories