I've made a python script that factorizes a number into its prime factors. However when dealing with big numbers i may like to have an idea to the progress of the computation. (I simplified the script)
import time, sys, threading
num = int(input("Input the number to factor: "))
factors = []
def check_progress():
but = input("Press p: ")
if but == "p":
tot = int(num**(1/2))
print("Step ", k, " of ", tot, " -- ", round(k*100/tot,5), "%", end="\r", sep="")
t = threading.Thread(target=check_progress) ?
t.daemon = True ?
t.start() ?
k = 1
while(k != int(num**(1/2))):
k = (k+1)
if num%k == 0:
factors.append(int(k))
num = num//k
k = 1
print(factors)
I'm wondering if there is a way to show the progress on demand, for example, during the loop, i press a key and it prints the progress?
How can i implement a thread of something like that in my script?
Thanks and sorry for my english
Edit:
def check_progress():
while True:
but = input("## Press return to show progress ##")
tot = int(num**(1/2))
print("Step ", k, " of ", tot, " -- ", round(k*100/tot,5), "%", sep="")
Here is one possible design:
Main thread:
create queue and thread
start the progress thread
wait user input
on input:
pop result from queue (may be None)
display it
loop
Progress thread:
do the work an put status in queue
I can provide example, but I feel you are willing to learn. Feel free to comment for help.
Edit: Full example with queue.
from time import sleep
from Queue import Queue
from threading import Thread
# Main thread:
def main():
# create queue and thread
queue = Queue()
thread = Thread(target=worker, args=(queue,))
# start the progress thread
thread.start()
# wait user input
while thread.isAlive():
raw_input('--- Press any key to show status ---')
# pop result from queue (may be None)
status = queue.get_nowait()
queue.task_done()
# display it
if status:
print 'Progress: %s%%' % status
else:
print 'No status available'
# Progress thread:
def worker(queue):
# do the work an put status in queue
# Simulate long work ...
for x in xrange(100):
# put status in queue
queue.put_nowait(x)
sleep(.5)
if __name__ == '__main__':
main()
Related
I have a python script that prints a spinner. This spinner, hopefully, will last until stopped.
spinnerFrames = [
"/",
"-",
"\\",
"|",
]
def spinner():
i = 0
while True:
clearScreen() #function to clear the screen
print(spinnerFrames[i])
i = i + 1
if (i == 3):
i = 0
sleep(0.15)
spinner()
sleep(3)
# break out here
print("Done!")
I know you can do sys.stdout.write() and then only delete that line, but that's beside the point.
I can't figure out the best way to stop the loop and exit the function. (To continue on in my code)I'd like to be able to break from the loop down where you call it, as I hope to make this a Pip package.
This, I assume is possible, though I don't know how to do it. Thanks for your help!
You need to run it asynchronously, like how the multiprocessing library allows you to do. When you create a separate thread, you'll be left with a handle on it that you can use to kill it when you want it to stop.
from multiprocessing import Process
from time import sleep
spinnerFrames = [
"/",
"-",
"\\",
"|",
]
def spinner():
i = 0
while True:
print(spinnerFrames[i], end='\r')
i = i + 1
if (i == 3):
i = 0
sleep(0.15)
if __name__ == '__main__':
p = Process(target=spinner)
p.start()
sleep(3)
p.terminate()
print("Done!")
Here is a reference implementation from one of my projects. It prints dots instead of a spinner, but it is trivial to change:
import threading
import time
def indicate_wait(func):
active = threading.Lock()
def dot_printer():
while active.locked():
print('.', end='', flush=True)
time.sleep(1)
def wrapper(*args, **kwargs):
t = threading.Thread(target=dot_printer)
active.acquire()
t.start()
res = func(*args, **kwargs)
active.release()
return res
return wrapper
Example:
#indicate_wait
def test():
time.sleep(5)
record when it started, then break loop if current time - start time >
duration.
import time
spinnerFrames = [
"/",
"-",
"\\",
"|",
]
def spinner():
i = 0
startTime = time.time()# record starting time
duration = 3
while True:
clearScreen() #function to clear the screen
print(spinnerFrames[i])
i = i + 1
if (i == 3):
i = 0
if time.time() - startTime > duration:
break
sleep(0.15)
spinner()
print("Done!")
I have made a thread that is supposed to show the seconds passing. Unfortunately, when I use getstr from the curses module the whole script stops, including the thread. I have to use a thread lock to stop random characters being printed out because of overlapping orders.
Any suggestions on how to fix this or an alternative would be great!
In the below example window and window2 are already set-up...
lock = threaing.Lock()
def main_function():
#starts thread
t1 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
The problem with my code
I figured out the problem with my code. You can't run a thread inside a thread for some reason and I originally had my main function called to be considered a thread. I guess I should have stated this in my question. Sorry
There is probably a way to run a thread in a thread, but this did not work for me.
My Updated Code
lock = threading.Lock()
def call_threads():
t1 = threading.Thread(target=main_function,args=(window1,))
t1.start()
t2 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
def main_function(window1):
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
If there is anything else that may have caused this error, please comment it!
Description: now, I have done input and countdown, both of which are carried out at the same time, but I want to achieve like this:
When I don't input anything during the countdown, it will execute another function after the countdown
When I input something before the end of the countdown, the countdown will pause, and then another function will be executed
My code is as follows:
import time
from threading import Thread
def waitinput():
wait_input_str = input("Please enter your account:\n")
print(wait_input_str)
thd = Thread(target=waitinput)
thd.daemon = True
thd.start()
for i in reversed(range(1, 11)):
print("\rcountdown:{}second".format(i), end="")
time.sleep(1)
# ###########################################
You can use isAlive() method to check if your thread has terminated.
In your case:
import time
from threading import Thread
def waitinput():
wait_input_str = input("Please enter your account:\n")
print(wait_input_str)
thd = Thread(target=waitinput)
thd.daemon = True
thd.start()
for i in reversed(range(1, 11)):
if not thd.isAlive():
# Execute 2
print("\nCountdown has stopped")
break
print("\rcountdown:{}second".format(i), end="")
time.sleep(1)
if thd.isAlive():
# Execute 1
print("\nCountdown has ended")
So I'm doing some testing with threads and I realised I could not stop and then start a thread. I could stop it, but starting it again was the issue.I want a script that adds 1 to a var when it is on then its stops when off by pressing shift to turn on and off.I have the detecting shift working (it is on another part of my code), but I just need to find out how to stop and start threadsHere is my test code:
from threading import Thread as th
import time as t
var = 0
def testDef():
global var
var += 1:
t.sleep(1)
test = th(target = testDef)
test.start()
while True:
menu = input("On, Off, Show Var")
if menu == "On":
test.start()
elif menu == "Off":
test._stop():
elif menu == "S":
print(var)
I know there are a few errors, but I mainly need the on and off threading to work.
Thanks, Jeff.
As far as I know, you can't actually stop and restart a thread as you can't use test.start() when the method has been terminated. However, you may be wondering to something similar by using threading.Condition to pause and later resume the execution.
You can read more about it in the documentation.
There is also an error in var += 1:, change it to var += 1
Here's a simple example on how to use threading.Event to enable two threads to communicate. This works by setting the internal flag of the Event to either True or False. While this internal flag is False you can ask thread a to wait (effectively block, which is not very efficient by the way). Then we use the two timers (b, c) to simulate a shift press every 5 seconds. In order to release a we set the event (internal flag = True). 5 seconds later, we clear the value of the internal flag and this will make thread a to block again.
import threading
def do(event):
flag = True
while flag:
if not event.isSet():
print "blocking"
event.wait()
else:
print "resuming"
def pressShift(event, enable):
print "Shift pressed"
if enable:
event.set()
else:
event.clear()
def main():
event = threading.Event()
a = threading.Thread(target=do, args=(event,))
b = threading.Timer(5, pressShift, args=(event, True)).start()
c = threading.Timer(10, pressShift, args=(event, False)).start()
a.start()
a.join()
if __name__ == "__main__":
main()
You cannot restart a thread that has already been started. What you can do, however, is to create another thread.
from threading import Thread as th
import time as t
var = 0
def testDef():
global var
var += 1
t.sleep(1)
test = th(target = testDef)
test.start()
while True:
menu = input("On, Off, Show Var")
if menu == "On":
test = th(target = testDef)
test.start()
elif menu == "Off":
test._stop()
elif menu == "S":
print(var)
Use an event object like this post, and check that event in your target functoin. Also, you need a new thread each time you re-start. The code shown below adds some debugging that should be useful. (Another approach is to build a custom stop function.)
import logging
import threading
import time as t
var = 0
logging.basicConfig(level=logging.DEBUG,
format='[%(levelname)s] (%(threadName)-10s) %(message)s',
)
def testDef(stop_event):
global var
print 'Thread Running', var
# inThread.stop()
while not stop_event.isSet():
var += 1
logging.debug('Var is %i' % var)
t.sleep(1)
# Use an event to track user input
testStopEvent = threading.Event()
testStopEvent.clear()
test = threading.Thread(name = 'test', target=testDef, args=((testStopEvent,)))
test.setDaemon(True)
while True:
menu = input("On = 1, Off = 2, Show Var = 3")
if menu == 1:
test.start()
elif menu == 2:
testStopEvent.set()
test.join() # Wait for the thread to finish
test = threading.Thread(target=testDef, args=((testStopEvent,))) # "re-start" thread
testStopEvent.clear() # Reset the stop event
elif menu == 3:
print(var)
I am working on a Python scripts that kicks off a thread with a loop and a raw_input so that user can enter commands. After this thread starts, main program starts a loop with another raw_input so that the user can enter commands.
How can this be organized so that the commands being inputted via console goes to the correct raw_input (main thread/concurrent thread)? At the moment, all inputs in the console are going to the main thread only.
Thanks
Example
import threading
def commThread():
while True:
chatAcceptance = raw_input("User")
t1 = threading.Thread(target=commThread)
t1.start()
while True:
userInput = raw_input("\nPlease insert a command:\n")
So this can be done via lock. I did a small code example that shows how to swap between one "scope" to the other using the raw_input.
import threading
lock = threading.Lock()
def inputReader(thread, prompt):
userInput = raw_input(prompt)
print thread + " " + userInput + "\n"
return userInput
def myThread1():
global lock
while True:
lock.acquire()
print "thread 1 got the lock\n"
while True:
threadInput = inputReader("thread 1", "from thread 1\n")
if threadInput == "release":
lock.release()
print "thread 1 released the lock\n"
break
def myThread2():
global lock
while True:
lock.acquire()
print "thread 2 got the lock\n"
while True:
threadInput = inputReader("thread 2", "from thread 2\n")
if threadInput == "release":
lock.release()
print "thread 2 released the lock\n"
break
t1 = threading.Thread(target=myThread1).start()
t2 = threading.Thread(target=myThread2).start()