为什么此python脚本在后台运行,消耗100%的CPU?


22

我想在后台运行一个简单的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()

这可以按预期工作,但是它消耗过多的CPU(100%CPU)。

如何在不消耗大量能量的情况下使其正常工作?


26
如果您所使用的框架完全支持,请使用基于事件的代码来检测剪贴板中的更改,而不是循环。持续获取剪贴板直到更改为止,或者听系统告诉您更改了剪贴板,这是有区别的。
Stefan

6
@dessert我从未在python中完成过,但是这似乎是GTK的解决方案:stackoverflow.com/a/25961646/985296(没有提及任何平台依赖性)。
Stefan

@ jpmc26&甜点看起来像个meta讨论,请随时关注。明确这个范围绝对是一个好主意。
桅杆

1
@dessert如果您和JPMC想要讨论此主题是开还是关,请打开一个元线程。请不要在此参数中使用注释。(注释清理完成,主题锁定了一个星期,等待您的元讨论,但同时也停止了评论争论)
托马斯·沃德

Answers:


44

time.sleep()while循环中忘记了它,根据此答案,SO睡眠0.2秒是轮询频率与CPU负载之间的一个很好的折衷:

import time

while True:
  get_clipboard()
  time.sleep(0.2) # sleep for 0.2 seconds

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

请注意,通常在一个循环中进行轮询的次数通常不被认为是好的设计。更好的方法是作用于事件改变剪贴板的内容,为GTK的例子,可以发现在这个SO答案

进一步阅读


3
您可以缩短睡眠间隔,而不会真正影响所用的CPU时间。我在Mac上发现:0.01 s:69%,0.02 s:43%,0.05 s:25%,0.1 s:14%,0.2 s:7%。0.5 s:3%
Floris

6
轮询仍然很糟糕,因为它一直在唤醒该进程,从而污染了CPU缓存等等。 正如注释中所讨论的那样,最好等待剪贴板更改的通知。
彼得·科德斯

@dessert:如果我知道答案,我会的。我只是建议在您的答案中提到,每0.2秒唤醒一次仍不被认为是一种好的设计,并且寻找一种非轮询方法会更好。但是对于仅在一台计算机上运行的一次性黑客,请确保它不是可怕的,并且可能足够好。
彼得·科德斯

26

我终于使它工作没有循环。这是代码:

我必须安装一些模块: 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()

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


噢,你为什么要clip.wait_for_text()两次?
wizzwizz4

@ wizzwizz4你是对的,我编辑过...战车
dmx

@ wizzwizz4不大家复制两次只是可以肯定的?
迈克尔·弗兰克

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)

3

我对这个项目很感兴趣,所以为在那种环境下更舒适的人写了一个bash脚本:

#!/bin/bash

xclip -o -sel clip > /tmp/LastClip

while true ; do 

    xclip -o -sel clip > /tmp/NewClip
    diff -q /tmp/LastClip /tmp/NewClip > /tmp/DiffClip
    if [[ -s /tmp/DiffClip ]] ; then
        cat /tmp/NewClip    # For testing dump to screen instead of printing
        cp -a /tmp/NewClip /tmp/LastClip
    fi
    sleep 1.0

done

它确实需要Xorg的xclip软件包:

sudo apt install xclip

它使用cat命令将剪贴板内容转储到屏幕上。如果要硬拷贝,请替换catlp并指定打印机名称,方向和可能的“适合页面”选项。

您会在屏幕上看到一些滞后,因为我选择sleep 1.0了在打印机上看不到的并且仍然比人们突出显示文本和使用Ctrl+ 更快C

如果将完全相同的突出显示的文本复制到剪贴板,则不会引起差异。一个字母或多或少会触发响应。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.