1

我在我的脚本中运行两个单独的进程。第一个进程 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()
4

1 回答 1

0

终于设法完成了这项工作。在上面的代码片段中,当我调用

listener.join()

对于 Keyboard Listener 事件,它实质上是阻塞了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消费者

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 上面评论中的建议。

于 2018-08-14T18:38:46.677 回答