在多个python进程之间交换基于击键的数据

时间:2018-08-08 12:36:10

标签: python multiprocessing python-multiprocessing pynput

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

1 个答案:

答案 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在以上评论中的建议。