我正在脚本中运行两个单独的进程。第一个进程p1启动一个oneSecondTimer例程,该例程恰好在1秒处执行并完成一些工作。第二个过程p2触发了键盘监听器,该监听器可以监听键盘。
此刻,我希望当用户按下退出键时p1进程停止。我尝试使用全局变量,但没有用。我尝试使用队列,但它确实有效,但这绝对不是最优雅的解决方案。它实际上是一个丑陋的解决方法,不会扩大规模。
最终,脚本将具有多个单独的并行进程,这些进程可以通过按各种键来控制(而不仅仅是启动/停止)。 这是代码,
import time
from pynput import keyboard
from multiprocessing import Process, Queue
def on_release(key):
if key == keyboard.Key.esc:
print('escaped!')
# Stop listener
return False
def keyboardListener(q):
with keyboard.Listener(on_release=on_release) as listener:
listener.join()
print('Keybord Listener Terminated!!!')
# Make the queue NOT EMPTY
q.put('Terminate')
def oneSecondTimer(q):
starttime = time.time()
# Terminate the infinite loop if
# queue is NOT EMPTY
while (not q.qsize()):
print("tick")
time.sleep(1.0 - ((time.time() - starttime) % 1.0))
return False
if __name__ == '__main__':
q = Queue()
p1 = Process(target=oneSecondTimer, args=(q,))
p1.start()
p2 = Process(target=keyboardListener, args=(q,))
p2.start()
答案 0 :(得分:0)
最终设法完成了这项工作。 在上面的代码段中,当我打电话
时listener.join()
对于键盘监听器事件,它实际上是阻止了其余的 keyboardListener(q)进程的执行,直到 on_release(key)函数 STOPPED 。因为这正是 .join()应该要做的。这是阻止呼叫。
在以下代码段中, keyboard.listener 线程只是在 keyboardListener(q)过程中启动。 while 循环跟踪名为 fetchKeyPress 的变量。变量按照名称的含义进行操作,它将在 on_release(key)子例程中获取按下的键。由fetchKeyPress获取的按键被泵入称为 q 的队列中,该队列在两个进程 keyboardListener(key)和 oneSecondTimer(q)之间共享。 keyboardListener进程的运行速度是oneSecondTimer进程的4倍,具有退出 while 循环的逻辑,并防止了如果用户连续/重复按相同的键,则导致队列泛滥。
oneSecondTimer(q)进程每秒运行一次。如果 q 不为空,则会吐出 q 中的所有内容。它还内置了一个 while 循环退出逻辑。
现在,我可以利用由过程 p2 获取的数据(按键),并将其用于其他并行运行过程 p1 。
p2 是生产者。 p1 是 Consumer 。
import time
from pynput import keyboard
from multiprocessing import Process, Queue
fetchKeyPress = 10
def on_release(key):
global fetchKeyPress
fetchKeyPress = key
if key == keyboard.Key.esc:
fetchKeyPress = 0
print('escaped!')
# Stop listener
return False
def keyboardListener(q):
global fetchKeyPress
prevKeyFetch = 10 # Keep track of the previous keyPress
keyboard.Listener(on_release=on_release).start()
while (fetchKeyPress):
print ('Last Key Pressed was ', fetchKeyPress)
# Fill the Queue only when a new key is pressed
if (not (fetchKeyPress == prevKeyFetch)):
q.put(fetchKeyPress)
# Update the previous keyPress
prevKeyFetch = fetchKeyPress
time.sleep(0.25)
print('Keybord Listener Terminated!!!')
q.put('Terminate')
def oneSecondTimer(q):
runner = True # Runs the while() loop
starttime = time.time()
while (runner):
print('\ttick')
if (not q.empty()):
qGet = q.get()
print ('\tQueue Size ', q.qsize())
print ('\tQueue out ', qGet)
# Condition to terminate the program
if (qGet == 'Terminate'):
# Make runner = False to terminate the While loop
runner = False
time.sleep(1.0 - ((time.time() - starttime) % 1.0))
return False
if __name__ == '__main__':
q = Queue()
p1 = Process(target=oneSecondTimer, args=(q,))
p1.start()
p2 = Process(target=keyboardListener, args=(q,))
p2.start()
但是我认为,归根结底,我可能只会使用https://pypi.org/project/keyboard/库。感谢@ toti08在以上评论中的建议。