Perché questo script python viene eseguito in background consumando il 100% di CPU?


22

Voglio eseguire un semplice script Python in background che legge il testo dagli Appunti e lo stampa. Ecco il mio codice

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

Funziona come previsto ma consuma troppa CPU (100% CPU).

Come posso farlo funzionare correttamente senza consumare così tanto?


26
Se supportato dal framework in uso, utilizzare il codice basato sugli eventi per rilevare le modifiche negli Appunti anziché un ciclo. C'è una differenza tra ottenere gli Appunti continuamente finché non cambia o ascoltare il sistema che ti dice che è cambiato.
stefan,

6
@dessert Non l'ho mai fatto in Python, ma qui sembra esserci una soluzione con GTK: stackoverflow.com/a/25961646/985296 (non menziona alcuna dipendenza dalla piattaforma).
stefan,

@ jpmc26 & dessert Sembra una meta discussione, sentiti libero di portarlo lì. Sicuramente una buona idea per chiarire questo ambito .
Mast

1
@dessert Apri un meta thread se tu e JPMC volete discutere se questo è un argomento attivo / non attivo. Si prega di non usare commenti per questo argomento. (Pulizia commento completata, argomento bloccato per una settimana in attesa della discussione Meta ma anche per interrompere l'argomento commento)
Thomas Ward

Risposte:


44

Hai dimenticato il time.sleep()nel tuo whileloop, secondo questa risposta su SO dormire per 0,2 secondi è un buon compromesso tra frequenza di polling e carico della CPU:

import time

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

Controllare gli appunti ogni 0,2 secondi sembra abbastanza spesso abbastanza spesso; se vuoi meno carico della CPU puoi persino aumentare questo valore: pochi utenti cambiano il contenuto degli appunti da un secondo all'altro.

Si noti che in generale il polling in un ciclo spesso non è considerato un buon design. Un approccio migliore sarebbe quello di agire in caso di modifica del contenuto degli appunti, un esempio per GTK può essere trovato in questa risposta SO .

Ulteriori letture


3
È possibile ridurre l'intervallo di sospensione senza influire sul tempo di CPU utilizzato. Ho trovato sul mio 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
Il polling fa ancora schifo perché continua a svegliare questo processo inquinando le cache della CPU e così via. Come discusso nei commenti, è molto meglio attendere la notifica di un cambiamento negli Appunti.
Peter Cordes,

@dessert: se conoscessi la risposta, lo farei. Suggerisco semplicemente di menzionare nella tua risposta che svegliarsi ogni 0,2 secondi non è ancora considerato un buon progetto e che cercare un approccio non polling sarebbe molto meglio. Ma per un hack una tantum che verrà eseguito solo su un computer, sicuramente non è orribile e probabilmente è abbastanza buono.
Peter Cordes,

26

Finalmente riesco a farlo funzionare senza loop. Questo è il codice:

Ho dovuto installare alcuni moduli: 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()

sentiti libero di scegliere la soluzione adatta a te.


Oooh ... Perché lo richiedi clip.wait_for_text()due volte?
wizzwizz4,

@ wizzwizz4 hai ragione ho modificato ... i carri armati
dmx

@ wizzwizz4 Non tutti copiano due volte solo per essere sicuri?
Michael Frank,

16

Stai eseguendo la cosa in un while True:ciclo! Ciò significa che la CPU esegue costantemente il loop. Basta aggiungere una piccola pausa lì e dovresti vedere precipitare l'utilizzo della 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

Sono stato incuriosito da questo progetto, quindi ho scritto uno script bash per quelli più a suo agio in quell'ambiente:

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

Richiede il xclippacchetto di Xorg :

sudo apt install xclip

Sta scaricando il contenuto degli appunti sullo schermo usando il catcomando. Se si desidera la copia cartacea invece sostituirla catcon lpe specificare il nome della stampante, l'orientamento e possibilmente l'opzione "adatta alla pagina".

Vedrai un po 'di ritardo sullo schermo perché scelgo sleep 1.0quale sarebbe invisibile con una stampante e ancora più veloce di quanto le persone possano evidenziare il testo e usare Ctrl+ C.

Se copi negli Appunti lo stesso identico testo evidenziato, ciò non determina alcuna differenza. Una lettera in più o in meno attiverà una risposta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.