I have a timer function which I am calling it in another function like this
import time
import threading
def f():
while(True):
print "hello"
time.sleep(5)
def execute():
t = threading.Timer(5,f)
t.start()
command = ''
while command != 'exit':
command = raw_input()
if command == 'exit':
t.cancel()
Even if after entering "exit" command, the function is printing "hello"
I am not able to figure out Whats wrong with the code
class threading.Timer - cancel() - Doc-Link
Stop the timer, and cancel the execution of the timer’s action. This will only work if the timer is still in its waiting stage.
A very simple Version of what you are trying to accomplish could look like this.
import threading
_f_got_killed = threading.Event()
def f():
while(True):
print "hello"
_f_got_killed.wait(5)
if _f_got_killed.is_set():
break
def execute():
t = threading.Timer(5,f)
t.start()
command = ''
while command != 'exit':
command = raw_input()
if command == 'exit':
_f_got_killed.set()
t.cancel()
execute()
For forcefully killing a thread look at this:
Is there any way to kill a Thread in Python?
You are using cancel wrong. In http://docs.python.org/2/library/threading.html, it states: "Timers are started, as with threads, by calling their start() method. The timer can be stopped (before its action has begun) by calling the cancel() method. The interval the timer will wait before executing its action may not be exactly the same as the interval specified by the user."
In your code, if you try to use cancel after the timed thread has already begun its execution (it will in 5 seconds), cancel accomplishes nothing. The thread will remain in the while loop in f forever until you give it some sort of forced interrupt. So typing "exit" in the first 5 seconds after you run execute works. It will successfully stop the timer before the thread even begins. But after your timer stops and your thread starts executing the code in f, there will be no way to stop it through cancel.
Related
I have a loop which makes a get request to a webservice to fetch data and do some stuff, but I want to 'manually' terminate the thread/event, which I achieved with the following example:
from threading import Event
exit = Event()
if external_condition():
exit.set()
for _ in range(mins):
fetch_data_and_do_stuff()
exit.wait(10) #wait 10 seconds
With that, the only thing that terminates it's the sleep time between loops. How can I also kill the loop so it doesn't keep running until it gets to the last iteration?
nvm i've solved it like this
from threading import Event
exit = Event()
if external_condition():
exit.set()
for _ in range(mins):
fetch_data_and_do_stuff()
if exit.wait(10):
break
the condition returns true when killed and also sleeps the 10 seconds, so it works
you have 2 options ,
kill the thread or process entirely
or making the loop's boolean false. going that way
you could use a global variable in this way: [Python 3.7] , run it to see
from threading import Thread
from time import sleep
global glob
glob=True
def threaded_function():
while glob:
print("\n [Thread] this thread is running until main function halts this")
sleep(0.8)
if __name__ == "__main__":
thread = Thread(target = threaded_function, args = ())
thread.start()
for i in range(4,0,-1):
print("\n [Main] thread will be terminated in "+str(i)+" seconds")
sleep(1)
glob=False
while True:
print("[Main] program is over")
sleep(1)
The point of my script is to have one function called stopper send a terminate thread event to the function go_to, once it reaches a certain time.
Currently, the event is triggered, the thread supposedly closed, and stopper is ended. But go_to continues to print to the command line.
I can't figure out how to stop it correctly.
import threading
import time
class Stop_Check(object):
def __init__(self):
self.thread1Stop = threading.Event()
def stopper(self):
t = 0
while True:
t = t + 1
time.sleep(1.0)
if t == 3 :
self.thread1Stop.set()
break
else :
print("I'm still going...")
time.sleep(1.0)
continue
print("terminated")
def go_to(self):
while (not self.thread1Stop.is_set()):
print("I am working!")
time.sleep(1.0)
def main(self):
t1 = threading.Thread(target=self.go_to)
t1.start()
self.stopper()
time.sleep(5.0)
if __name__ == '__main__' :
sc = Stop_Check()
sc.main()
I tried running the script in the terminal, outside of the software called Atom. Now it terminates as expected. Thanks to #Steven for confirming it works! Still not sure why this behavior was happening.
I'm not too familiar with threading, and probably not using it correctly, but I have a script that runs a speedtest a few times and prints the average. I'm trying to use threading to call a function which displays something while the tests are running.
Everything works fine unless I try to put input() at the end of the script to keep the console window open. It causes the thread to run continuously.
I'm looking for some direction in terminating a thread correctly. Also open to any better ways to do this.
import speedtest, time, sys, datetime
from threading import Thread
s = speedtest.Speedtest()
best = s.get_best_server()
def downloadTest(tries):
x=0
downloadList = []
for x in range(tries):
downSpeed = (s.download()/1000000)
downloadList.append(downSpeed)
x+=1
results_dict = s.results.dict()
global download_avg, isp
download_avg = (sum(downloadList)/len(downloadList))
download_avg = round(download_avg,1)
isp = (results_dict['client']['isp'])
print("")
print(isp)
print(download_avg)
def progress():
while True:
print('~ ',end='', flush=True)
time.sleep(1)
def start():
now=(datetime.datetime.today().replace(microsecond=0))
print(now)
d = Thread(target= downloadTest, args=(3,))
d.start()
d1 = Thread(target = progress)
d1.daemon = True
d1.start()
d.join()
start()
input("Complete...") # this causes progress thread to keep running
There is no reason for your thread to exit, which is why it does not terminate. A daemon thread normally terminates when your programm (all other threads) terminate, which does not happen in this as the last input does not quit.
In general it is a good idea to make a thread stop by itself, rather than forcefully killing it, so you would generally kill this kind of thread with a flag. Try changing the segment at the end to:
killflag = False
start()
killflag = True
input("Complete...")
and update the progress method to:
def progress():
while not killflag:
print('~ ',end='', flush=True)
time.sleep(1)
I have thrown together a quick threading test:
import threading
def test():
print "it don't work"
while True:
threading.Timer(1, test).start()
It runs test, but it doesn't wait. What's wrong?
In each loop iteration, you start a new thread. Therefore you will reach the limit of allowed thread and you will get an exception : can't start new thread.
while True:
threading.Timer(1, test).start()
You can add global flag and wait until the function is executed - You should use time.sleep to avoid busy waiting.
a = False
def test():
global a
print("hallo")
a = True
threading.Timer(10, test).start()
while not a:
time.sleep(1)
print('done')
I'm using Selenium Webdriver in my program in order to try and automate something. I am then parsing th resulting page, and checking for a specific element in the page. If the page doesn't have the specific element, then I use sched.scheduler to re-automate the task, by having the user click a button (in the Tkinter GUI). The button runs a function, which schedules a task for sched.scheduler, and has the task be sent to a function in which I created a new process from the multiprocessing module.
This is basically what it is:
import time
import sched
from multiprocessing import Process
#the function needs to run for the first time, then waits for user input if an error shows up
#if it's the second time around, the worker function runs the scheduler
global first_time_happening
first_time_happening = True
terminate = False
scheduler = sched.scheduler(time.time, time.sleep)
def worker():
#insert some working process here using selenium webdriver
print("Worker happened!")
global first_time_happening
if first_time_happening:
first_time_happening = False
elif not first_time_happening:
global relay_to_timer
relay_to_timer = scheduler.enter(5, 2, timer)
scheduler.run()
def process():
p = Process(target=worker)
#p.daemon = True
p.start()
def timer():
if not terminate:
global relay_to_process
relay_to_process = scheduler.enter(5, 2, process)
scheduler.run()
if terminate:
scheduler.cancel(relay_to_process)
scheduler.cancel(relay_to_timer)
def quit_button():
global terminate
terminate = True
if scheduler.empty:
print("The line is empty")
elif not scheduler.empty:
print("Something in the queue!")
while not scheduler.empty:
scheduler.cancel(relay_to_process)
scheduler.cancel(relay_to_timer)
worker()
#simulating where the GUI asks a question, person presses a button, and the button redirects them
#to function worker()
worker()
#simulating a user press the quit button
quit_button()
It keeps running even after I "hit" quit (or call the quit function in this case). I keep getting the queue is empty, but I'm not sure why it isn't working? Any help is appreciated, thanks!!
The scheduler keeps running even with an empty queue just in case somebody (presumably another thread) entered something again. I believe the way to make it end is to raise an exception (whether from the action or delay function) -- .run will propagate it and you can catch it.
To wit...
class AllDoneException(Exception): pass
def worker():
#insert some working process here using selenium webdriver
print("Worker happened!")
global first_time_happening
if first_time_happening:
first_time_happening = False
elif not first_time_happening:
global relay_to_timer
relay_to_timer = scheduler.enter(5, 2, timer)
try:
scheduler.run()
except AllDoneException:
pass
and in function timer
if terminate:
raise AllDoneException