Warum wird dieses Python-Skript im Hintergrund ausgeführt und beansprucht 100% der CPU?

22

Ich möchte ein einfaches Python-Skript im Hintergrund ausführen, das Text aus der Zwischenablage liest und druckt. Hier ist mein Code.

#!/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()

Dies funktioniert wie erwartet, verbraucht jedoch zu viel CPU (100% CPU).

Wie kann ich es richtig machen, ohne so viel zu verbrauchen?

dmx
quelle
26
Wenn dies von dem verwendeten Framework überhaupt unterstützt wird, verwenden Sie ereignisbasierten Code, um Änderungen in der Zwischenablage und nicht in einer Schleife zu erkennen. Es ist ein Unterschied, ob Sie die Zwischenablage kontinuierlich abrufen, bis sie sich ändert, oder ob Sie dem System zuhören, wenn Sie erfahren, dass sich die Zwischenablage geändert hat.
Stefan
6
@dessert Ich habe es noch nie in Python gemacht, aber hier scheint eine Lösung mit GTK zu sein: stackoverflow.com/a/25961646/985296 (erwähnt keine Plattformabhängigkeit).
Stefan
@ jpmc26 & dessert Sieht aus wie eine Metadiskussion, zögern Sie nicht, sie dort aufzunehmen. Auf jeden Fall eine gute Idee, dies für den Anwendungsbereich aufzuklären .
Mast
1
@dessert Öffnen Sie einen Meta-Thread, wenn Sie und JPMC diskutieren möchten, ob dieses Thema aktiviert oder deaktiviert ist. Bitte verwenden Sie keine Kommentare für dieses Argument. (Bereinigung der Kommentare abgeschlossen, Thema für eine Woche bis zur Metadiskussion gesperrt, aber auch um das Kommentarargument zu beenden)
Thomas Ward

Antworten:

44

Sie haben das time.sleep()in Ihrer whileSchleife vergessen , laut dieser Antwort ist SO- Sleeping für 0.2s ein guter Kompromiss zwischen Polling-Frequenz und CPU-Last:

import time

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

Das Überprüfen der Zwischenablage alle 0,2 Sekunden scheint häufig genug zu sein. Wenn Sie weniger CPU-Auslastung möchten, können Sie diesen Wert sogar erhöhen. Nur wenige Benutzer ändern den Inhalt der Zwischenablage von einer Sekunde zur nächsten.

Beachten Sie, dass im Allgemeinen das Abrufen in einer Schleife so oft nicht als gutes Design angesehen wird. Ein besserer Ansatz wäre, auf den Fall einer Änderung des Inhalts der Zwischenablage zu reagieren. Ein Beispiel für GTK finden Sie in dieser SO-Antwort .

Weitere Lektüre

Dessert
quelle
3
Sie können das Ruheintervall verkürzen, ohne die verwendete CPU-Zeit wirklich zu beeinträchtigen. Ich fand auf meinem 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
Die Abfrage ist immer noch nicht erfolgreich, weil sie diesen Prozess immer wieder aufweckt und die CPU-Caches verschmutzt und so weiter. Wie in den Kommentaren besprochen ist es viel besser, auf die Benachrichtigung über eine Änderung in der Zwischenablage zu warten.
Peter Cordes
@dessert: Wenn ich die Antwort wüsste, würde ich. Ich schlage lediglich vor, in Ihrer Antwort zu erwähnen, dass das Aufwachen alle 0,2 Sekunden immer noch nicht als a betrachtet wird gutes Design angesehen wird, und die Suche nach einem nicht abfragenden Ansatz wäre viel besser. Aber für einen einmaligen Hack, der nur auf einem Computer ausgeführt wird, ist das sicher nicht schrecklich und wahrscheinlich gut genug.
Peter Cordes
26

Ich mache es endlich ohne Schleife. Dies ist der Code:

Ich musste einige Module installieren: 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()

Wählen Sie einfach die für Sie passende Lösung.

dmx
quelle
Oooh ... Warum fragst du clip.wait_for_text()zweimal?
wizzwizz4
@ wizzwizz4 du hast recht ich bearbeitet ... tanks
dmx
@ wizzwizz4 Kopiert nicht jeder zweimal, nur um sicherzugehen?
Michael Frank
16

Sie führen das Ding in einer while True:Schleife! Das bedeutet, dass die CPU ständig Ihre Schleife ausführt. Fügen Sie dort einfach eine kleine Pause hinzu, und Sie sollten feststellen, dass die CPU-Auslastung stark abfällt:

#!/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)
terdon
quelle
3

Ich war fasziniert von diesem Projekt und schrieb ein Bash-Skript für diejenigen, die sich in dieser Umgebung besser auskennen:

#!/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

Dafür ist das Xorg- xclipPaket erforderlich :

sudo apt install xclip

Der Inhalt der Zwischenablage wird mit dem catBefehl auf dem Bildschirm abgelegt . Wenn Sie stattdessen einen Ausdruck wünschen, ersetzen Sie ihn catdurch lpund geben Sie Ihren Druckernamen, die Ausrichtung und möglicherweise die Option "An Seite anpassen" an.

Sie werden eine gewisse Verzögerung auf dem Bildschirm bemerken, da ich auswähle, sleep 1.0was mit einem Drucker nicht zu bemerken wäre und immer noch schneller ist, als Menschen Text hervorheben und Ctrl+ verwenden können C.

Wenn Sie genau denselben hervorgehobenen Text in die Zwischenablage kopieren, wird kein Unterschied ausgelöst. Ein Buchstabe mehr oder weniger löst eine Antwort aus.

WinEunuuchs2Unix
quelle