Why is this python script running in background consuming 100 % CPU?

22,917

Solution 1

You forgot the time.sleep() in your while loop, according to this answer on SO sleeping for 0.2s is a good compromise between polling frequency and CPU load:

import time

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

Checking the clipboard every 0.2 seconds seems easily often enough; if you want less CPU load you can even increase this value – few users change the clipboard content from one second to another.

Note that in general polling in a loop as often as that is not considered good design. A better approach would be to act on the event of changing the clipboard content, an example for GTK can be found in this SO answer.

Further reading

Solution 2

I finally make it work a without loop. This is the code:

I had to install few 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()

feel free to choose the solution that fits for you.

Solution 3

You are running the thing in a while True: loop! That means that the CPU is constantly running your loop. Just add a small pause there and you should see the CPU usage drop precipitously:

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

Solution 4

I was intrigued by this project so wrote a bash script for those more comfortable in that environment:

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

It does require Xorg's xclip package:

sudo apt install xclip

It's dumping clipboard contents to screen using cat command. If you want hard copy instead replace cat with lp and specify your printer name, orientation and possibly "fit to page" option.

You will see a bit of lag to screen because I choose sleep 1.0 which would be unnoticeable with a printer and still faster than people can highlight text and use Ctrl+C.

If you copy the exact same highlighted text to the clipboard it doesn't trigger a difference. One letter more or less will trigger a response.

Share:
22,917

Related videos on Youtube

dmx
Author by

dmx

Updated on September 18, 2022

Comments

  • dmx
    dmx almost 2 years

    I want to run a simple python script in the background that reads text from the clipboard and prints it out. Here is my 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()
    

    This is working as expected but it consumes too much CPU (100% CPU).

    How can I make it work correctly without consuming that much?

    • stefan
      stefan about 5 years
      If at all supported by the framework you're using, use event-based code to detect changes in the clipboard rather than a loop. There's a difference between getting the clipboard continuously until it changes or to listen to the system telling you that it changed.
    • stefan
      stefan about 5 years
      @dessert I haven't ever done it in python, but here seems to be a solution with GTK: stackoverflow.com/a/25961646/985296 (doesn't mention any platform dependency).
    • Mast
      Mast about 5 years
      @jpmc26 & dessert Looks like a meta discussion, feel free to take it up there. Definitely a good idea to get this cleared up for scope.
    • Thomas Ward
      Thomas Ward about 5 years
      @dessert Open a meta thread if you and JPMC want to discuss whether this is on/off topic. Please do not use comments for this argument. (Comment cleanup complete, topic locked for a week pending your Meta discussion but to also stop the comment argument)
  • Floris
    Floris about 5 years
    You could make the sleep interval shorter without really affecting the CPU time used. I found on my 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%
  • Peter Cordes
    Peter Cordes about 5 years
    Polling still sucks because it keeps waking up this process polluting CPU caches and so on. As discussed in comments much better to wait for notification of a clipboard change.
  • Peter Cordes
    Peter Cordes about 5 years
    @dessert: If I knew the answer, I would. I merely suggest mentioning in your answer that waking up every 0.2 seconds is still not considered a good design, and looking for a non-polling approach would be much better. But for a one-off hack that is only going to run on one computer, sure it's not horrible, and is probably good enough.
  • wizzwizz4
    wizzwizz4 about 5 years
    Oooh… Why are you requesting clip.wait_for_text() twice?
  • dmx
    dmx about 5 years
    @wizzwizz4 you are right I edited ... tanks
  • Michael Frank
    Michael Frank about 5 years
    @wizzwizz4 Doesn't everyone copy twice just to be sure?