2

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.

6
  • you need a thread running in parallel Commented Jan 13, 2017 at 21:18
  • look in internet for getch() - it is not standard command and may not work with some consoles. Commented Jan 13, 2017 at 21:29
  • possible duplication: Python read a single character from the user Commented Jan 13, 2017 at 21:32
  • @furas I don't think it's about getting the character... I think he needs to know how to get it to work simultaneously. Commented Jan 13, 2017 at 21:37
  • @Aaron getch() doesn't block code - it doesn't wait for key - so you can use it in loop and do other thing simultaneously Commented Jan 13, 2017 at 21:44

2 Answers 2

4

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
Sign up to request clarification or add additional context in comments.

Comments

1

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.

1 Comment

for i in range(0, itrs) seems to need :, i.e. for i in range(0, itrs):

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.