为什么这个 python 脚本在后台运行会消耗 100% 的 CPU?

dmx*_*dmx 23 python scripts clipboard

我想在后台运行一个简单的 python 脚本,从剪贴板读取文本并将其打印出来。这是我的代码。

#!/usr/bin/env python

import Tkinter

last_clipboard = ""

def get_clipboard():
  global last_clipboard
  root = Tkinter.Tk()
  root.withdraw() # Hide the main window (optional)
  text_in_clipboard = root.clipboard_get()
  if text_in_clipboard != last_clipboard:
    last_clipboard = text_in_clipboard
    print last_clipboard


while True:
  get_clipboard()
Run Code Online (Sandbox Code Playgroud)

这按预期工作,但消耗太多 CPU(100% CPU)。

如何在不消耗那么多的情况下使其正常工作?

des*_*ert 46

你忘记了time.sleep()在你的while循环中,根据这个关于 SO sleep 0.2s 的答案是轮询频率和 CPU 负载之间的一个很好的折衷:

import time

while True:
  get_clipboard()
  time.sleep(0.2) # sleep for 0.2 seconds
Run Code Online (Sandbox Code Playgroud)

每 0.2 秒检查一次剪贴板似乎很容易;如果您希望减少 CPU 负载,您甚至可以增加此值——很少有用户将剪贴板内容从一秒更改为另一秒。

请注意,通常在循环中轮询如此频繁不被认为是好的设计。更好的方法是对更改剪贴板内容的事件采取行动,可以在此 SO answer 中找到 GTK 的示例。

进一步阅读

  • 轮询仍然很糟糕,因为它不断唤醒这个污染 CPU 缓存的进程等等。[正如评论中所讨论的](https://askubuntu.com/questions/1143959/why-is-python-script-running-in-background-consumer-100-cpu#comment1897976_1143959) 更好地等待剪贴板的通知改变。 (6认同)
  • 您可以缩短睡眠间隔,而不会真正影响使用的 CPU 时间。我在 Mac 上发现:0.01 秒:69%、0.02 秒:43%、0.05 秒:25%、0.1 秒:14%、0.2 秒:7%。0.5 秒:3% (3认同)

dmx*_*dmx 27

我终于让它无循环地工作。这是代码:

我不得不安装几个模块: sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0

#!/usr/bin/env python3
import gi, sys
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk

last_clipboard = ""

def callBack(*args):
  global last_clipboard
  new_clipboard = clip.wait_for_text()
  if new_clipboard != last_clipboard:
    last_clipboard = new_clipboard
    print("new Clipboard")
    print(new_clipboard)

clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
clip.connect('owner-change',callBack)
Gtk.main()
Run Code Online (Sandbox Code Playgroud)

随意选择适合您的解决方案。


ter*_*don 16

你正在while True:循环运行这个东西!这意味着 CPU一直在运行您的循环。只需在此处稍作停顿,您就会看到 CPU 使用率急剧下降:

#!/usr/bin/env python

import Tkinter
import time

last_clipboard = ""

def get_clipboard():
  global last_clipboard
  root = Tkinter.Tk()
  root.withdraw() # Hide the main window (optional)
  text_in_clipboard = root.clipboard_get()
  if text_in_clipboard != last_clipboard:
    last_clipboard = text_in_clipboard
    print last_clipboard

while True:
  get_clipboard()
  time.sleep(1)
Run Code Online (Sandbox Code Playgroud)