免责声明:导入语句在函数内,我知道这很罕见。我在这里展示我的整个程序,是在讲述我的问题和想法的同时,逐个功能地展示它。实际上,我在做一些不同的事情,我只是为这个Stackoverflow问题做了一个最小的例子。有重复的问题,但是我在其中找不到很好的答案,因为那些问题只说“使用多线程”(例如this answer)。这个特定的问题与如何使用多线程有关。
故事:我正在用Python运行程序。假设这是一个进入无限循环的while循环。它只是运行愉快。例如,
def job(threadname, q):
from time import sleep
c = 0
while True:
sleep(0.1) #slow the loop down
c += 1
print(c)
我想做的是,它异步检测到stdin
上的按键,然后中断执行,这样我就可以在被中断的函数中执行我想做的任何事情(或者如果我正在运行)它与python3 -i program.py
一起使用,以便在装入我所有模块的情况下切换到REPL,请记住,这是一个最小的示例,在该示例中,我不想过多强调此类问题。
我的想法是:我有一个函数可以异步获取按键,然后通过队列将其发送到另一个线程,然后它可以工作。因此,我将工作职能扩展为:
def job(threadname, q):
from time import sleep
c = 0
while True:
sleep(0.1) #slow the loop down
c += 1
print(c)
ch = q.get() #extension for multithreading
handle_keypress(ch) #extension for handling keypresses
handle_keypress(ch)
的代码是:
def handle_keypress(key):
if (key == "q"):
print("Quit thread")
exit(0)
elif (key == "s"):
print("would you like to change the step size? This has not been implemented yet.")
else:
print("you pressed another key, how nice! Unfortunately, there are not anymore options available yet.")
换句话说,除了展示我希望能够做到这一点之外,没什么有趣的。
起初,问题似乎出在job()
函数中。罪魁祸首是q.get()
,它正在悬挂。但是,它挂起是因为我的输入线程出于某种原因不是异步的并且阻塞了。我不知道如何使其畅通无阻。
这是我的输入线程的功能:
def get_input(threadname, q):
#get one character, this code is adapted from https://stackoverflow.com/questions/510357/python-read-a-single-character-from-the-user
while True:
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
q.put(ch)
对我来说,sys.stdin.read(1)
很明显是受阻的,但我不知道如何使其不受阻。在现在的状态下,我也想不出一种解决毒丸问题的方法,这就是q.get()
函数中job()
被阻止的原因。
我通过调用以下函数来运行程序:
def run_program():
from threading import Thread
from queue import Queue
queue = Queue()
thread1 = Thread( target=get_input, args=("Thread-1", queue) )
thread2 = Thread( target=job, args=("Thread-2", queue) )
thread1.start()
thread2.start()
thread1.join()
thread2.join()
我的问题:这是您如何设计用于处理异步按键的程序?如果是这样,如何使get_input()
函数不受阻碍?
答案 0 :(得分:0)
多亏了Sav,我找到了回答这个问题的方法。我认为,他的评论就是答案。因此,如果他将重写他的评论。我接受他的回答。现在,我将展示为了使非阻塞实现正常工作而更改的代码部分:
def job(threadname, q):
from queue import Empty
from time import sleep
c = 0
while True:
sleep(0.1) #slow the loop down
c += 1
print(c)
#Below is the changed part
ch = None
try:
ch = q.get(block=False)
except Empty:
pass
if ch is not None:
handle_keypress(ch)