Im trying to write a module for Python that prints out text for my program and displays a progress bar while i do something in the background. Im using the 'threading' module currently but open to suggestions if something else will make it easier.
what i want to know is two fold, how should i call this class elegantly and how should i stop these threads im creating?
this is what im currently doing:
tmp1 = textprint("hello this is text")
tmp1.start()
# do something
tmp1.stop()
these are the options ive considered and looked into so far:
using thread.name to find the name of the thread or having the thread
return a name to kill afterwards. OR passing a number for similar
thread identification afterwards. (a bit cumbersome and not my
favourite solution.)
sending a thread.event ? - from reading the docs i see an event can
be sent, perhaps that can be used to stop it?
or a with statement but im unclear how to use it in this context, plus i find most of the python docs extremely confusing and not written for me at all.
what i would like to do is something like this:
echo('hello') (prints progress bar etc)
- and then when i want to stop it echo.stop()
the obv. problem there though is that the stop function doesnt know which thread it is trying to stop.
Here is a skeleton of what im trying to do:
import time
import string
import threading
class print_text(threading.Thread):
def __init__(self,arg=None):
super(print_text,self).__init__()
self._stop = False
self.arg=arg
def run (self):
# start thread for text
print self.txt
while not self._stop:
print "rude words"
def echo (self,txt):
self.txt=txt
self.start()
def stop(self):
self._stop = True
def stopped(self):
return self._stop == True
def __enter__(self):
print "woo"
return thing
def __exit__(self, type, value, traceback):
return isinstance(value, TypeError)
if __name__ == '__main__':
print_text.start.echo('this is text') # dunt werk
with print_text.echo('this is text'):
time.sleep(3)
print "done"
and then call it like so:
echo('this is text')
i also guess to do this i would have to
import echo from print_text
the WITH way of doing things suggests putting an __enter__ and __exit__ bit in. i tried them and they didnt work and also, i didnt know what i was doing, really appreciate any help, thanks.
You were very close to having working code. There just needed to be a few minor fixups:
print_text is a class. It should be instantiated with print_text()
The start method returns an instance of print_text, you need to save that
in order to call stop and echo on it: t = print_text()
The enter method needs to return self instead of thing.
The exit method should either set _stop or call stop().
The echo method should return self so that it can be used with the with-statement.
Here is some working code that includes those minor edits:
import time
import string
import threading
class print_text(threading.Thread):
def __init__(self, arg=None):
super(print_text,self).__init__()
self._stop = False
self.arg=arg
def run (self):
# start thread for text
print self.txt
while not self._stop:
print "rude words"
def echo (self, txt):
self.txt=txt
self.start()
return self
def stop(self):
self._stop = True
def stopped(self):
return self._stop == True
def __enter__(self):
print "woo"
return self
def __exit__(self, type, value, traceback):
self._stop = True
return isinstance(value, TypeError)
if __name__ == '__main__':
t = print_text()
t.echo('this is text')
time.sleep(3)
t.stop()
with print_text().echo('this is text'):
time.sleep(3)
print "done"
The best way to stop a thread in Python is to politely ask it to stop. The best way to pass new data to a thread is with the Queue module.
Both are used in the code in this post, which demonstrates socket communication from a Python thread but is otherwise relevant to your question. If you read the code carefully you'll notice:
Using threading.Event() which is set by a method call from outside, and which the thread periodically checks to know if it was asked to die.
Using Queue.Queue() for both passing commands to the thread and receiving responses from it.
A thread name is useful if you could potentially have multiple subthreads running the same target at once and want to ensure that all of them are stopped. It seems like a useful generalization and doesn't seem too cumbersome to me, but beauty is in the eye of the beholder :-). The following:
starts a subthread to print a message and start a progressbar
stops the subthread using a name given when it was started.
It is much simpler code. Does it do what you want?
import time, threading
class print_text:
def __init__(self):
pass
def progress(self):
while not self._stop: # Update progress bar
print(".", sep="", end="")
time.sleep(.5)
def echo(self, arg="Default"): # Print message and start progress bar
print(arg)
self._stop = False
threading.Thread(target=self.progress, name="_prog_").start()
def stop(self):
self._stop = True
for t in threading.enumerate():
if t.name == "_prog_":
t.join()
tmp1 = print_text()
tmp1.echo("hello this is text")
time.sleep(10)
tmp1.stop()
print("Done")
Related
I am pretty new to Python and have a question about threading.
I have one function that is called pretty often. This function starts another function in a new Thread.
def calledOften(id):
t = threading.Thread(target=doit, args=(id))
t.start()
def doit(arg):
while true:
#Long running function that is using arg
When calledOften is called everytime a new Thread is created. My goal is to always terminate the last running thread --> At all times there should be only one running doit() Function.
What I tried:
How to stop a looping thread in Python?
def calledOften(id):
t = threading.Thread(target=doit, args=(id,))
t.start()
time.sleep(5)
t.do_run = False
This code (with a modified doit Function) worked for me to stop the thread after 5 seconds.
but i can not call t.do_run = False before I start the new thread... Thats pretty obvious because it is not defined...
Does somebody know how to stop the last running thread and start a new one?
Thank you ;)
I think you can decide when to terminate the execution of a thread from inside the thread by yourself. That should not be creating any problems for you. You can think of a Threading manager approach - something like below
import threading
class DoIt(threading.Thread):
def __init__(self, id, stop_flag):
super().__init__()
self.id = id
self.stop_flag = stop_flag
def run(self):
while not self.stop_flag():
pass # do something
class CalledOftenManager:
__stop_run = False
__instance = None
def _stop_flag(self):
return CalledOftenManager.__stop_run
def calledOften(self, id):
if CalledOftenManager.__instance is not None:
CalledOftenManager.__stop_run = True
while CalledOftenManager.__instance.isAlive():
pass # wait for the thread to terminate
CalledOftenManager.__stop_run = False
CalledOftenManager.__instance = DoIt(id, CalledOftenManager._stop_flag)
CalledOftenManager.__instance.start()
# Call Manager always
CalledOftenManager.calledOften(1)
CalledOftenManager.calledOften(2)
CalledOftenManager.calledOften(3)
Now, what I tried here is to make a controller for calling the thread DoIt. Its one approach to achieve what you need.
I'm looking for this question online but I can not find any way to do it directly I'm trying the following
class Test(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
for i in range(3):
time.sleep(1)
print(i)
def main():
test = Test()
test.start()
del test
time.sleep(5)
print('end')
main()
the only way to stop the thread is from the run method when the code ends but I can not find any way to end the thread.
You can't. All you can do is ask it nicely (by implementing some sort of inter thread communication like a threading.Queue object, then making your thread check it for instructions) and hope for the best.
You can use this simple approach to stop/kill/end a child thread from the parent thread using some variable that is being checked in child thread periodically:
from threading import Thread
from time import time, sleep
class Test:
some_var = True
def __init__(self):
self.t = Thread(target=self.worker)
#self.t.setDaemon(True)
self.t.start()
def worker(self):
while self.some_var is True:
print("%s > I'm running" % str(time()))
test = Test()
sleep(2)
test.some_var = False
print("End!")
Let me know if I didn't understand your question, but I think I've answered your question "How to end with a thread from the main thread?".
This is part of a complex project, I will try and simplify it.
I have a class that gets a callable and executes it, the callable can run for any duration of time. If I get a signal (can be using Signal or any other flag I watch) to terminate I want to terminate the callable's execution on the spot (without exiting the process of course)
class FooRunner(object):
def goo(self, foo):
try:
foo()
except:
pass
def on_stop_signal(self):
pass
On a single-threaded signal not running on Windows, (i.e., any Unix flavor) you can use signal.alarm for that.
Check the first example on the documentation - it is more or less what you are asking for:
https://docs.python.org/2/library/signal.html
If anyone ever needs this here is a code sample of it working (One thing to note signal.signal can be called only from the main thread):
#!/usr/bin/python
import time
import signal
import threading
class MyException(Exception):
pass
class FooRunner(object):
def goo(self, foo):
try:
signal.signal(signal.SIGALRM, self.on_stop_signal)
foo()
except MyException:
print('caugt alarm exception')
def on_stop_signal(self, *args):
print('alarm triggered')
raise MyException()
def sample_foo():
time.sleep(30)
def stop_it():
signal.alarm(3)
print('alarm was set for 3 seconds')
if __name__ == "__main__":
print('starting')
fr = FooRunner()
t = threading.Thread(target=stop_it)
t.start()
fr.goo(sample_foo)
Thanks #jsbueno
This is part of a complex project, I will try and simplify it.
I have a class that gets a callable and executes it, the callable can run for any duration of time. If I get a signal (can be using Signal or any other flag I watch) to terminate I want to terminate the callable's execution on the spot (without exiting the process of course)
class FooRunner(object):
def goo(self, foo):
try:
foo()
except:
pass
def on_stop_signal(self):
pass
On a single-threaded signal not running on Windows, (i.e., any Unix flavor) you can use signal.alarm for that.
Check the first example on the documentation - it is more or less what you are asking for:
https://docs.python.org/2/library/signal.html
If anyone ever needs this here is a code sample of it working (One thing to note signal.signal can be called only from the main thread):
#!/usr/bin/python
import time
import signal
import threading
class MyException(Exception):
pass
class FooRunner(object):
def goo(self, foo):
try:
signal.signal(signal.SIGALRM, self.on_stop_signal)
foo()
except MyException:
print('caugt alarm exception')
def on_stop_signal(self, *args):
print('alarm triggered')
raise MyException()
def sample_foo():
time.sleep(30)
def stop_it():
signal.alarm(3)
print('alarm was set for 3 seconds')
if __name__ == "__main__":
print('starting')
fr = FooRunner()
t = threading.Thread(target=stop_it)
t.start()
fr.goo(sample_foo)
Thanks #jsbueno
This question already has answers here:
Is there any way to kill a Thread?
(31 answers)
Closed 8 years ago.
I did a little search and found out there is no way to kill a thread in python, but how would one solve a problem like me ?
I have a function that sets X to True for one hour and after that it sets it back to False.
sometimes the program finishes less than the needed hour, but the thread is still running and make garbage in memory.
def enableX():
self.x=True
sleep(3600)
self.x=False
def function1():
self.enableXThread=Thread(target=self.enableX)
self.enableXThread.start()
any idea ? how I can kill enbableXThread when the program terminates no matter if the thread is done or not ?
how I can kill enbableXThread when the program terminates
If the thread does not have any cleanup to do, make it a daemon thread by setting enableXThread.daemon to True. This must be done before starting the thread:
self.enableXThread = Thread(target=self.enableX)
self.enableXThread.daemon = True
self.enableXThread.start()
Otherwise, use an exit flag (a global variable that the threads check to see whether they should exit) or an Event handler.
You might also considering using a signal for this, as this may be simpler than threading; you can simply set an alarm for an hour and have the handler reset the variable. If your process ends before the alarm goes off, nothing happens. Note that this isn't available on Windows.
import signal
X = False
def handle_alarm(signum, frame):
global X
X = False
signal.signal(signal.SIGALRM, handle_alarm)
def set_X_true_then_false_later(secs=3600):
global X
X = True
signal.alarm(secs)
It looks like your problem has already been solved using kindall's suggestions, but if you ever are interested in being able to terminate a thread from another one, the following might be of interest to you.
If you do not mind your code running about ten times slower, you can use the Thread2 class implemented below. An example follows that shows how calling the new stop method should kill the thread on the next bytecode instruction.
import threading
import sys
class StopThread(StopIteration): pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
class Thread3(threading.Thread):
def _bootstrap(self, stop_thread=False):
def stop():
nonlocal stop_thread
stop_thread = True
self.stop = stop
def tracer(*_):
if stop_thread:
raise StopThread()
return tracer
sys.settrace(tracer)
super()._bootstrap()
################################################################################
import time
def main():
test = Thread2(target=printer)
test.start()
time.sleep(1)
test.stop()
test.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
if __name__ == '__main__':
main()
The Thread3 class appears to run code approximately 33% faster than the Thread2 class.