This is for my first program. I am trying to put this loading animation in a while loop, but it gives this error after the second "f.start()". As I don't understand much about threads, the "help" I could find on Google was not helpful at all, which involved long codes with class creation and everything. Can somebody help me understand what I could do here?
I copied the animation code from here: Python how to make simple animated loading while process is running
import itertools
import threading
import time
import sys
#here is the animation
def animate():
for c in itertools.cycle(['|', '/', '-', '\\']):
if done:
break
sys.stdout.write('\rloading ' + c)
sys.stdout.flush()
time.sleep(0.25)
sys.stdout.write('\rDone! ')
t = threading.Thread(target=animate)
while True:
done = False
user_input = input('Press "E" to exit.\n Press"S" to stay.')
if user_input is "E":
break
elif user_input is "S":
# Long process here
t.start()
time.sleep(5)
done = True
time.sleep(1)
print("\nThis will crash in 3 seconds!")
time.sleep(3)
break
# Another long process here
t.start()
time.sleep(5)
done = True
As the error says, a thread can only be started once. So, create a new thread instead. Notice also that I use join to wait for the old thread to stop.
import itertools
import threading
import time
import sys
#here is the animation
def animate():
for c in itertools.cycle(['|', '/', '-', '\\']):
if done:
break
sys.stdout.write('\rloading ' + c)
sys.stdout.flush()
time.sleep(0.25)
sys.stdout.write('\rDone! ')
t = threading.Thread(target=animate)
while True:
done = False
user_input = input('Press "E" to exit.\n Press"S" to stay.')
if user_input is "E":
break
elif user_input is "S":
# Long process here
t.start()
time.sleep(5)
done = True
t.join()
print("\nThis will crash in 3 seconds!")
time.sleep(3)
break
# Another long process here
done = False
t = threading.Thread(target=animate)
t.start()
time.sleep(5)
done = True
Related
So, i would claim that i understand how Asyncio, Multiprocessing, Threading etc. works, basically. I know how to listen for keystrokes too - there are many good examples on this site.
However i was unable to combine both into one. I have a programm that runs continously in a loop, until it runs into certain cases where it stops. In these cases, it uses a Multiprocessing.Queue() to prompt for user input on wether it should continue or not.
All of this works, so far so good. Now i want to add a second catch case here: The programm should, once it starts running, immediatly cease working as soon as i press a certain button (lets say Escape).
This is the very dumbed down version of my programm:
test.py:
from test3 import Counter
from multiprocessing import Process, Queue
import sys
def main(q, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p1.join()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, user_Input)
else:
sys.exit()
if __name__ == "__main__":
q = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, passed_variable=user_Input)
test3.py:
import time
class Counter:
def counting(self, q, user_input):
x = 0
while True:
print(str(x) + " " + user_input)
if x == 4:
q.put(False)
break
time.sleep(1)
x += 1
I tried everything i could think of, in no case did i get the desired result, and no question i found here was able to help me in this specific case.
You can solve this using keyboard and then creating a second Queue():
from test3 import Counter
from multiprocessing import Process, Queue
import sys
import keyboard
def main(q, queue2, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p2 = Process(target=keyCatcher, args=(queue2,))
p2.start()
if queue2.get() == False:
p1.terminate()
print("Terminating Programm")
sys.exit()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, queue2, user_Input)
else:
sys.exit()
def keyCatcher(queue2):
while True:
if keyboard.is_pressed('q'): # if key 'q' is pressed
queue2.put(False)
if __name__ == "__main__":
q = Queue()
queue2 = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, queue2, passed_variable=user_Input)
The crux is:
p1.start()
p1.join()
Which means after main() starts p1, it waits for it to finish. So there's no chance to interrupt it while processing.
You need to:
wait for p1 to finish
while waiting, see if the main process gets a 'q'
if the main process gets a 'q', stop it.
Something like:
p1.start()
while p1.is_alive():
k = keyboard.read_key()
if k == 'q':
p1.terminate()
Hey I am trying to have a loop be pausable from user input like having a input box in the terminal that if you type pause it will pause the loop and then if you type start it will start again.
while True:
#Do something
pause = input('Pause or play:')
if pause == 'Pause':
#Paused
Something like this but having the #Do something continually happening without waiting for the input to be sent.
Ok I get it now, here is a solution with Threads:
from threading import Thread
import time
paused = "play"
def loop():
global paused
while not (paused == "pause"):
print("do some")
time.sleep(3)
def interrupt():
global paused
paused = input('pause or play:')
if __name__ == "__main__":
thread2 = Thread(target = interrupt, args = [])
thread = Thread(target = loop, args = [])
thread.start()
thread2.start()
You can't directly, as input blocks everything until it returns.
The _thread module, though, can help you with that:
import _thread
def input_thread(checker):
while True:
text = input()
if text == 'Pause':
checker.append(True)
break
else:
print('Unknown input: "{}"'.format(text))
def do_stuff():
checker = []
_thread.start_new_thread(input_thread, (checker,))
counter = 0
while not checker:
counter += 1
return counter
print(do_stuff())
I have two files. One with a game with an evil gambler and the other with a loading function to play out between the lines of text. My goal is to replace the time.sleep() functions with my loading function. The first file looks like this:
import random
import time
import test
def game():
string_o = "Opponent "
string_u = "User "
input_n = ""
input_n = input('Care to try your luck?\n')
while input_n == 'yes' or input_n == 'y':
cpu = random.randint(1,6)
user = random.randint(1,6)
time.sleep(0.5)
print('\nGreat!')
time.sleep(0.2)
input_n=input("\nAre you ready?\n")
time.sleep(0.4)
print(string_o , cpu)
#If the gambler's die roll is above three he gets very happy
if cpu > 3:
print('Heh, this looks good')
time.sleep(0.2)
#...but if it's lower he gets very anxious
else:
('Oh, no!')
test.animate()
print(string_u , user)
if cpu < user:
print('Teach me, master')
else:
print('Heh, better luck next time, kid')
time.sleep()
input_n = input('\nDo you want to try again?\n')
print("Heh, didn't think so.\nPlease leave some room for thr big boys")
game()
The other file looks like this:
import itertools
import threading
import time
import sys
done = False
#here is the animation
def animate():
for c in itertools.cycle(['|', '/', '-', '\\']):
if done:
break
sys.stdout.write('\rloading ' + c)
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\rDone! ')
t = threading.Thread(target=animate)
t.start()
#would like an x here instead that is defined in the other file
time.sleep(1)
done = True
The problem is that the function animate() plays out before the game has even started.
I would also like to set the time for the loading function in my main game file. Is that possible?
By putting t.start() outside of any function in your test.py, you are running animate as soon as you import test.py. You should put t.start() inside a function instead. Also, your done flag is also set to True when test.py is imported and will always immediately break your for loop inside animate. I don't think you really need this flag at all. Change your test.py to:
import itertools
import threading
import time
import sys
#here is the animation
def animate():
for c in itertools.cycle(['|', '/', '-', '\\']):
sys.stdout.write('\rloading ' + c)
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\rDone! ')
def start():
t = threading.Thread(target=animate)
t.start()
And then in your first file, instead of calling test.animate() directly, call test.start() instead.
I want to run a program that can ask for input and run threads at the same time.
For example:
import threading
def get_input():
while True:
var = input('prompt> ')
do_stuff
#main loop
while True:
input_thread = threading.Thread(target=get_input)
input_thread.start()
do_stuff_that_doesn't_work
So the problem above would be that it asks for input(prompt>) and while it's asking for input, do_stuff_that_doesn't_work won't work.
I've seen people get by this before but I don't know how to do it.
You shouldn't be creating a thread inside your while loop. Try this code...
import threading
import time
run = True
def get_input():
global run
while run:
var = input('prompt> ') #python 3 only
print('Input was ', var)
if 'q' == var:
run = False
input_thread = threading.Thread(target=get_input)
input_thread.start()
print('Type q to exit')
ctr = 0
while run:
ctr += 1
time.sleep(0.1)
print('Exiting with ctr: ', ctr)
import time
from threading import Timer
from random import randint
print("Every wrong answer is a 3s delay; you have 30s")
end = False
def lose():
print(end)
print("Time up!")
time.sleep(1)
print("Score is",pts,", with",wrong,"wrong answers.")
time.sleep(1)
input("enter to quit")
quit()
timer = Timer(10,lose)
timer.start()
pts = 0
wrong = 0
while end == False:
a = randint(5,50)
b = randint(5,50)
print(a,"+",b)
ans = input()
if ans.isnumeric():
ans = int(ans)
if ans == a+b:
print("correct")
pts = pts+1
else:
print("wrong,",a+b)
wrong = wrong+1
print("delay")
time.sleep(3)
print("delay end")
print("")
When the timer finishes, the loop overlaps the 'lose' function, and it messes up on the line like this:
Time up!
45 + 10
55
Score iscorrect
3
, with29 0+ wrong answers.37
enter to quitwrong,p
66
delay
How do I fix this issue?
Sorry if this question has already been answered, but I want to know.
Ideally, you should probably avoid using threads altogether, as mentioned in the comments.
However, if you are going to use threads, consider using a mutex to ensure that multiple threads are not trying to write to stdout at the same time.
For example:
# setup at the beginning:
from threading import Thread, Lock
mutex = Lock()
# surrounding each print statement:
mutex.acquire()
try:
print('text')
finally:
mutex.release()