繁体   English   中英

Python3:异步检测按键并将它们传达给主线程

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

免责声明 :import语句在函数内,我知道这很罕见。 我在这里展示我的整个程序,是在讲述我的问题和想法的同时,逐个功能地展示它。 实际上,我在做一些不同的事情,我只是为这个Stackoverflow问题做了一个最小的例子。 有重复的问题,但是我没有在其中找到好的答案,因为那些人​​只说“使用多线程”(例如, 此答案 )。 这个特定问题与如何使用多线程有关。

故事 :我正在用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运行它) 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()函数不受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) 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM