This question already has answers here:
Thread that I can pause and resume?
(2 answers)
Closed 4 years ago.
I would like to stop a running thread from outside a class, how it's possible
For example I have that broadcasting thread:
class BroadcastThread(Thread):
def __init__(self, converter, websocket_server):
super(BroadcastThread, self).__init__()
self.converter = converter
self.websocket_server = websocket_server
self.bRun = False
def run(self):
try:
while self.bRun:
print(self.bRun)
buf = self.converter.stdout.read1(32768)
if buf:
self.websocket_server.manager.broadcast(buf, binary=True)
elif self.converter.poll() is not None:
break
finally:
self.converter.stdout.close()
and I use it as follows from another class
self.broadcast_thread = BroadcastThread(self.output.converter, websocket_server)
and I need to start and stop it using the following methods
def start_broadcast_stream(self):
self.broadcast_thread.bRun = True
def stop_broadcast_stream(self):
self.broadcast_thread.bRun = False
The variable bRun is not updated at all by using the functions start_broadcast and stop
That is the common way in python and should work, but it will have the chance of stopping only every time the condition of the while is evaluated. You must guarantee the inside of the loop does not block, or takes very long time to run.
If you want to be able to cancel inside the loop, you need to slice things thinner (for example read 10 times a 1/10th of the data) and intercalate several checks of the bRun condition + breaks between them. Not pretty...
Edit: For added safety, bRun could be a Threading.Event, but I don't see the problem in this simple case.
Related
This question already has answers here:
Python async: Waiting for stdin input while doing other stuff
(3 answers)
Closed 4 months ago.
I want it so that my code continuously replaces itself continuously, and while that executes, I want the input to just take what it is without needing to press enter. I'm an android user and I've already tried downloading non-built-in-modules, so I can't use the keyboard module or anything like that.
My code is basically:
while game == "on":
print("string")
inpu = input
time.sleep(1)
clear screen
Apologies for false text editing or bad "code grammar."
I'm new to coding and stack overflow.
NOT wait for user input while in a loop?
Solution
That is easy, using multi-thread or multi-process. i.e create another thread that handles the input separately.
Demo of full code
Here is a very simple demo of multi-thread to begin.
import _thread
args = None
# Define a function for the thread
def mythread(threadname):
global args
args = input("input anything: ")
# Create one threads as follows
try:
_thread.start_new_thread( mythread, ("UI",) )
while args==None: # mimic your work loop
pass;
print("main loops end demo end")
except:
print ("Error: unable to start thread")
To run
$ python3 demo.py
Output
input anything: hello
main loops end demo end
I would like to exit a function by pressing a button using the return statement in the if statement. To write these lines again and again and again is not really what I like. That's why I am basically looking for a function that tells the parent function to return.
Obviously I can't use the return statement in a function and just execute the function where I want to check the variable, although that would be the nicest way I could imagine.
I want to explain it in a loop, but please keep in mind that's not where I want to use it. The usage is for automated processes which should have many exit points.
import keyboard, time
RedFlag = False
def set_RedFlag():
global RedFlag
RedFlag = True
keyboard.add_hotkey("end", set_RedFlag)
PauseFlag = False
def set_PauseFlag():
global PauseFlag
print(PauseFlag)
if PauseFlag == False:
PauseFlag = True
else:
PauseFlag = False
keyboard.add_hotkey("space", set_PauseFlag)
def task():
for i in range(30):
print("test",i)
time.sleep(1)
# Flags
if RedFlag == True: # exitpoint
return
while PauseFlag == True: # pause the script
time.sleep(1/6)
task()
Really relevant is the if statement after #Flags. Especially with the while statement I would have to repeat multiple lines. I would love to have this in one single word as if it was a function.
Edit:
More about the "what for?":
I would like to run a macro and later maybe other tasks. For example writing the odd numbers from 1 to 511. And I want to be able to stop or pause it at any given time.
I forgot to mention, that I tried using the multiprocessing module, since I could terminate the task there. Sadly it is not an option for me not only because the starting time of a process is a bit too long for me, also I am learning a bit about kivy and I know it get's complicated when I want to start another process while using kivy.
this is the first time I am reaching out with a question so hopefully I get the format right.
I am trying to limit the running time of my function (lets call it 'recursive_tsp_function') that is called from inside another function. This function recursive_tsp_function sometimes (not always) for unknown reasons keeps running infinitely.
CONTEXT:
Already, I tried implementing some sort of time checks like this
def recursive_tsp_function(parameters)
start = time.time()
... (function here)
now = time.time()
if (now - start) > max_time:
return
... (function continues)
But for some reason my kernel in debugging mode keeps running the recursive function infinitely until I manually pauze the running and go on step by step in the debugger and than it does register the time checks and than stops the function like it should.
NOW:
Because that approach didn't work I looked a better method online and came upon working with threads. I now have the following method based an a simple online example:
'Countdown' is my timer function (in the same file as the 'above_function').
The structure of my function above 'above_function' you can see below (note that it threads the timer).
Also I added a 'check' function to the same file as the above_function that checks whether the timer has run out. I did this because there was a problem with referring to the global variable my_timer from the recursive_tsp_function which is located in a different file (I would think my_timer being a global variable would make it accessible from other functions but anyway that seems to be resolved for now)
def countdown(max_time_timer):
global my_timer
my_timer = max_time_timer
for x in range(max_time_timer):
my_timer = my_timer - 1
time.sleep(1)`
def check():
global my_timer
if my_timer ==0:
return False
else: return True
def above_function(...):
...
countdown_thread = threading.Thread(target = countdown(10))
countdown_thread.start()
route = recursive_tsp_function(parameters)
...
return route
And than in a different file I have the recursive_tsp_function that would look something like this where I routinely run the check function from above and check whether my_timer is 0 yet:
def recursive_tsp_function(variables):
...
if not check():
return
...
return recursive_tsp_function(variables)
The PROBLEM that I have with this setup is there seems to be no threading taking place, the timer first runs out and only than the function recursive_tsp_function would run. Naturally this function stops immediately because the timer is already on 0.
Thank you for being patient with my long explanation. If anybody got tips on how to tackle a timer on a function like this I would be very grateful.
you should create the thread like this.
# target is the callable object
# args is the argument tuple for the target invocation
countdown_thread = threading.Thread(target = countdown, args=(10,))
What if you try
maxtime = int(input("What is the time for the timer?"))
import time
time_went = 0
for i in maxtime:
time_went = i
time.sleep(1)
And then instead of using time_went == 0 you can use time_went == maxtime?
This question already has answers here:
Keyboard input with timeout?
(28 answers)
Closed 2 years ago.
I'm writing a program in Python 3.8. I'd like to make an input, let's say variable v. If v is input as "n," then some code is run. Any other input does nothing. Additionally, if the time runs out and nothing is inputted for v, then the "n" code is run.
I've tried a couple of different timers which work alright, but I'm struggling on how to cancel the input, since it stops my whole program and won't proceed onto the code I want to run.
Here's what I have:
def timerMethod():
timeout = 10
t = Timer(timeout, print, ['Sorry, times up'])
t.start()
prompt = "You have %d seconds to choose: are you feeling ok? y/n: \n" % timeout
answer = input(prompt)
if (answer == "n"):
feelingBad = True
t.cancel()
The two problems that I've encountered are 1. feelingBad (global variable) will never be made true. I feel like this is a basic Py principle that I've forgotten here, and I can change the way the code is written here, but if you'd like to point out my error please do. The main problem 2. is that if there is no input for the answer variable, the timer will end but the program will not proceed. If someone could please help me on the right track as on how to cancel the input prompt when the timer runs out, I'd greatly appreciate it.
Check the multithreading
here. I wish there was a better explanation on how it works. In my own words, one thread starts and sets the start time which is taken up by the second. Instead of a timer that counts down, it runs an if statement which compares the time taken with the time limit, which gives a space for any code to be run before the program exits.
You can try this:
import time
from threading import Thread
user = None
def timeout():
cpt = 0
while user == None:
time.sleep(1); cpt += 1
if user != None:
return
if cpt == 10:
break
print("Pass")
Thread(target = timeout).start()
user = input()
I already asked a question about this yesterday, but now I have another :) im trying to write a text effects type class for my terminal apps to use - it does stuff like position cursor, clear screen, colour selection inside the echo string with colours preceded by an '#', random case, colour cylcling and other fun stuff (partly to aid my learning of python and partly for usefulness) - if I wanted to have parts of my class not be a thread how would I do it ? at the moment I have this spinner thing working (whole code here) but I want to call it multiple times. like this:
s=spin()
s.echo('##') # clears screen
# at the moment - here i get an error because only one thread can be started
s.echo('#red this is red #green green etc...')
the echo function does a lot of stuff as you can see if you look at the pastebin, so i need to call that quite a bit, but multiple calls result in 'only one thread' allowed error. perhaps i should be doing it a different way. This was the basic old code before the pastebin stuff.
spinner="▏▎▍▌▋▊▉█▉▊▌▍▎" #utf8
#convert the utf8 spinner string to a list
chars=[c.encode("utf-8") for c in unicode(spinner,"utf-8")]
class spin(threading.Thread):
def __init__(self):
super(spin,self).__init__()
self._stop = False
def run (self):
pos=0
while not self._stop:
sys.stdout.write("\r"+chars[pos])
sys.stdout.flush()
time.sleep(.15)
pos+=1
pos%=len(chars)
def cursor_visible(self):
os.system("tput cvvis")
def cursor_invisible(self):
os.system("tput civis")
def stop(self):
self._stop = True
def stopped(self):
return self._stop == True
Only the run method is actually running in a diffrent thread. The problem with your code is that you try to start the thread more than one time (in the echo method). You should check if the thread is already started (look at self._stop) before starting.
def echo (self, arg=None, sep=' ', end='\n', rndcase=True, txtspeed=0.03, bnum=0, spsw=True):
print cursave,
self.cursor_invisible()
# do you have to do all this ?
# c0m4: Only if you need all of those to be accessible for the spin object when echo ends
self.arg=arg
self.sep=sep
self.end=end
self.rndcase=rndcase
self.txtspeed=txtspeed
self.bnum=bnum
self.spsw=spsw
pos=0
cmd, txt = [reset], []
spsw=True
last_colour=''
txtpos=0
if arg:
# test if spinner is wanted and set the text position to be moved across a bit to allow for it
if spsw is True:
txtpos=4
self.start()
The last line if where the troubles start. It is not possible to start a thread more then once. Therefore you need to check if the thread is running before you restart it. Add something like
self.running = False
to your init method, and then set it in the run method
self.running = True
Then you can check the status of the object (thread running or not) like this:
if not self.running:
self.start()
If you need to run the initial portion of run regardless, you should put that in a separate method, like this:
def resetThread():
self.pos = 0