【问题标题】:Script consuming extreme amounts of CPU消耗大量 CPU 的脚本
【发布时间】:2021-10-18 05:46:53
【问题描述】:

我有一个程序,它在按住鼠标时将鼠标移动某个坐标,当松开鼠标键时它会停止。但是,下面的代码有时会占用我 90% 以上的 CPU。如何使下面的代码更高效/占用更少的 CPU 资源?

import pynput
import pyautogui

delta_x = [1,2,3]
delta_y = [3,2,1]
def on_press_start(*args):
    if args[-1]:
        return False

def on_press_loop(*args):
    if not args[-1]:
        return False



while True:
    i = 0
    with Listener(on_click=on_press_start) as listener:
        listener.join()

    with Listener(on_click=on_press_loop) as listener:
        for i in range(len(delta_x)):
            pyautogui.move(delta_x[i],delta_y[i])
            if not listener.running:
                break
            print(i)

【问题讨论】:

  • 你试过在你的 while 循环中添加 sleep() 吗?
  • @Tranbi,感谢您的评论,但我希望在每次循环迭代/鼠标单击和释放之间有尽可能少的延迟

标签: python pyautogui pynput


【解决方案1】:

根据https://pynput.readthedocs.io/en/latest/mouse.html

鼠标监听器是一个threading.Thread,所有的回调都会从线程中调用。

这意味着您创建的侦听器越多,它创建的 CPU 线程就越多,您有一个真正的循环,它将创建大量侦听器和大量线程,因为您的程序占用了过多的 CPU。

【讨论】:

  • 我将如何停止监听器,在 while 循环结束时使用 Listener.stop 或 listener.stop() ?两者似乎都有效,我应该使用哪一个?
  • @jr123456jr987654321 如果你不使用while True循环应该没问题,我没有真正理解循环的意义。侦听器本身是一个守护进程并且永无止境(除非被杀死或退出),因此它不一定需要一个 while 循环。
  • 只要单击并释放鼠标,while 循环就允许执行多次宏,我使用 Listener.stop 运行了一些测试并没有真正起作用。那么我该如何杀死 Listener?
  • 这不是要杀死听众,而是要生成一次而不是无限次。我建议多了解一下监听器的工作原理以及它的用途
  • 您不必创建多个侦听器!单个侦听器可以一次又一次地侦听同一事件。
【解决方案2】:

即使是简单的

while True:
    pass

循环将使用 100% 的 CPU 内核。循环内代码的效率只会影响频率。除非你限制频率,否则它不会影响 CPU 使用率。

在您的情况下,您不需要 while 循环来监视鼠标。库提供的侦听器会为您执行此操作,但以更智能的方式。来自docs

# create a listener
listener = mouse.Listener(on_click=on_click)

...

# start listening to clicks
listener.start()

...

# stop listening to clicks
listener.stop()

何时开始/停止监听鼠标事件取决于您的用例。

使用 on_click 和 on_move 事件的示例:

from pynput import mouse

if __name__ == "__main__":
    state = {
        "left_button_pressed": False
    }

    def on_click(x, y, button, pressed):
        if button == mouse.Button.left:
            state["left_button_pressed"] = pressed
            print("onclick", x, y, button, pressed)

    def on_move(*args):
        if state["left_button_pressed"]:
            print("on_move", *args)

    with mouse.Listener(on_click=on_click, on_move=on_move) as listener:
        listener.join()

【讨论】:

  • 感谢您的回答,这似乎是最可能的原因。删除 while 循环时,整个函数只运行一次(一次单击和一次长时间发布),是否可以将您对代码的更改(在问题中提供)合并到您的答案中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-01
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
  • 2012-11-23
  • 2011-03-15
  • 1970-01-01
相关资源
最近更新 更多