Python3 : detect keypresses asynchronously and communicate them to the main thread

标签 python python-3.x multithreading keyboard stdin

免责声明:导入语句位于函数内,我知道这并不常见。我在这里通过展示它的功能来展示我的整个程序,同时讲述我的问题和我的想法。事实上,我正在做一些不同的事情,我只是为了这个 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) 正在阻塞,但我不知道如何使其解锁。以现在的状态,我也想不出处理毒丸情况的方法,这就是为什么job()函数中的q.get()正在阻塞。

我通过调用以下函数来运行程序:

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() 函数畅通无阻?

最佳答案

感谢 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) 

关于Python3 : detect keypresses asynchronously and communicate them to the main thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56536288/

相关文章:

Python telnet 连接失败

检查线程是否正在运行

c# - 为什么额外的异步操作使我的代码比操作根本没有发生时更快?

python - 替换为换行符 python

Python 列表操作,Lambda 表达式

python - python 函数中有多少个 try/except 就太多了

python - 登录系统时运行 Python 脚本? [xubuntu 15.04]

python - 如何将 numpy 数组存储为 tfrecord?

Python,从生成器中生成的紧凑方法

java - 可以向父线程抛出异常吗