Reputation: 16998
I am running sequential code in a loop that is doing various computations, and occasionally printing out results that I monitor in the console.
What I'd like to do is be able to hit keyboard buttons, while the program is running, and then save and process that input (e.g. as a command to change some parameter) on the next start iteration of that loop.
Here's the structure of the code I'm running:
for i in range(0, itrs):
# ideally at the start of each loop:
# check to see if user pressed keybutton during prev loop itr,
# but don't wait / poll for it!
# userKeyInput = checkIfUserPressedKey()
# param = modify(userKeyInput)
doSequentialComputation(param)
Would the solution involve some notion of threading or interrupt? I could probably come up with a solution that involves file I/O, which wouldn't be terrible, but I was thinking maybe Python has something simpler that would work.
Upvotes: 2
Views: 14819
Reputation:
Use a thread to run the doSequentialComputation
function and pass param
to it as a thread argument:
import threading
t = threading.Thread(target=doSequentialComputation, args=(param,))
t.daemon = True
t.start()
Any modification to param
in the main thread will be seen by the code in the thread. Be sure to protect access to param
using a threading.Lock
:
param_lock = threading.Lock()
userKeyInput = checkIfUserPressedKey()
with param_lock:
parm = modify(userKeyInput)
Putting it all together:
import threading
class Parameter(object):
pass
def doSequentialComputation(param, param_lock):
itrs = 1000
param_copy = None
with param.lock:
param_copy = param
for i in range(0, itrs)
with param.lock:
if param.has_changed:
param_copy = param
param.has_changed = False
compute(param_copy)
def main():
param = Parameter()
param.has_changed = False
param.lock = threading.Lock()
args=(param, param_lock)
compute_thread = threading.Thread(target=doSequentialComputation, args=args)
compute_thread.daemon = True
compute_thread.start()
while True:
userKeyInput = checkIfUserPressedKey()
with param.lock:
param = modify(userKeyInput, param)
param.has_changed = True
The Parameter
class allows us to create an object to which we can add arbitrary attributes.
Upvotes: 1
Reputation: 11075
If you want python to do two things at once (get user input and compute) at the same time the easiest thing to do is use separate threads (separate processes are harder and not necessary in this instance). The high level threading
library is quite easy to get started with and I suggest a once-over of the docs, but here's a quick example:
from threading import Thread,Lock
import time
class globalVars():
pass
G = globalVars() #empty object to pass around global state
G.lock = Lock() #not really necessary in this case, but useful none the less
G.value = 0
G.kill = False
def foo(n): #function doing intense computation
for i in range(n):
if G.kill:
G.kill = False
return
time.sleep(n) #super intense computation
with G.lock:
G.value += i
t = Thread(target=foo, args=(10,))
t.start()
def askinput():
#change to raw_input for python 2.7
choice = input("1: get G.value\n2: get t.isAlive()\n3: kill thread\nelse: exit\ninput: ")
if choice == "1":
with G.lock:
print(G.value)
elif choice == "2":
print(t.is_alive())
elif choice == "3":
G.kill = True
else:
return 0
return 1
while askinput():
pass
Upvotes: 4