web-dev-qa-db-fra.com

Pourquoi ce script python exécuté en arrière-plan consomme-t-il 100% de CPU?

Je veux exécuter un simple script python en arrière-plan qui lit le texte du presse-papiers et l'imprime. Voici mon 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()

Cela fonctionne comme prévu mais consomme trop de CPU (100% CPU).

Comment puis-je le faire fonctionner correctement sans consommer autant?

23
dmx

Vous avez oublié le time.sleep() dans votre boucle while, selon cette réponse sur SO dormir pendant 0,2 s est un bon compromis entre la fréquence d'interrogation et la charge CPU:

import time

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

Vérifier le presse-papiers toutes les 0,2 secondes semble assez souvent; si vous voulez moins de charge CPU, vous pouvez même augmenter cette valeur - peu d'utilisateurs modifient le contenu du presse-papiers d'une seconde à l'autre.

Notez qu'en général, l'interrogation dans une boucle aussi souvent que cela n'est pas considérée comme une bonne conception. Une meilleure approche serait d'agir sur l'événement de modification du contenu du presse-papiers, un exemple pour GTK peut être trouvé dans ce SO réponse .

Lectures complémentaires

44
dessert

Je l'ai finalement fait fonctionner sans boucle. Voici le code:

J'ai dû installer quelques modules: 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()

n'hésitez pas à choisir la solution qui vous convient.

27
dmx

Vous exécutez la chose dans un while True: boucle! Cela signifie que le CPU exécute constamment votre boucle. Ajoutez-y simplement une petite pause et vous devriez voir la consommation du processeur diminuer brutalement:

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

J'ai été intrigué par ce projet, j'ai donc écrit un script bash pour ceux qui sont plus à l'aise dans cet environnement:

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

Il nécessite le package xclip de Xorg:

Sudo apt install xclip

Il vide le contenu du presse-papiers sur l'écran à l'aide de la commande cat. Si vous souhaitez plutôt une copie papier, remplacez cat par lp et spécifiez le nom de votre imprimante, son orientation et éventuellement l'option "Ajuster à la page".

Vous verrez un peu de décalage à l'écran car je choisis sleep 1.0 qui serait imperceptible avec une imprimante et encore plus rapide que les gens peuvent mettre en surbrillance du texte et utiliser Ctrl+C.

Si vous copiez exactement le même texte en surbrillance dans le presse-papiers, cela ne déclenchera pas de différence. Plus ou moins une lettre déclenchera une réponse.

4
WinEunuuchs2Unix