Mengapa skrip python ini berjalan di latar belakang mengkonsumsi CPU 100%?

22

Saya ingin menjalankan skrip python sederhana di latar belakang yang membaca teks dari clipboard dan mencetaknya. Ini kode saya.

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

Ini berfungsi seperti yang diharapkan tetapi mengkonsumsi CPU terlalu banyak (CPU 100%).

Bagaimana saya bisa membuatnya bekerja dengan benar tanpa mengkonsumsi sebanyak itu?

dmx
sumber
26
Jika didukung oleh framework yang Anda gunakan, gunakan kode berbasis acara untuk mendeteksi perubahan di clipboard daripada loop. Ada perbedaan antara mendapatkan clipboard terus menerus hingga berubah atau mendengarkan sistem yang memberi tahu Anda bahwa itu berubah.
Stefan
6
#: 33811 dddk Saya tidak pernah melakukannya dengan python, tetapi di sini tampaknya menjadi solusi dengan GTK: stackoverflow.com/a/25961646/985296 (tidak menyebutkan ketergantungan platform).
Stefan
@ jpmc26 & hidangan penutup Sepertinya diskusi meta, silakan bawa ke sana. Jelas merupakan ide yang bagus untuk membereskan ruang lingkup ini .
Tiang
1
@dabut Buka utas meta jika Anda dan JPMC ingin membahas apakah topik ini aktif / tidak aktif. Tolong jangan gunakan komentar untuk argumen ini. (Pembersihan komentar selesai, topik dikunci selama seminggu sambil menunggu diskusi Meta Anda tetapi juga untuk menghentikan argumen komentar)
Thomas Ward

Jawaban:

44

Anda lupa time.sleep()di whileloop Anda , menurut jawaban ini pada SO tidur untuk 0.2s adalah kompromi yang baik antara frekuensi polling dan beban CPU:

import time

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

Memeriksa clipboard setiap 0,2 detik sepertinya cukup mudah; jika Anda ingin lebih sedikit beban CPU, Anda bahkan dapat meningkatkan nilai ini - beberapa pengguna mengubah konten clipboard dari satu detik ke yang lain.

Perhatikan bahwa dalam polling umum dalam satu lingkaran sesering yang tidak dianggap desain yang baik. Pendekatan yang lebih baik akan bertindak pada acara mengubah isi clipboard, contoh untuk GTK dapat ditemukan dalam jawaban SO ini .

Bacaan lebih lanjut

pencuci mulut
sumber
3
Anda bisa memperpendek interval tidur tanpa benar-benar memengaruhi waktu CPU yang digunakan. Saya temukan di Mac saya: 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
Polling masih menyebalkan karena terus bangun proses ini mencemari cache CPU dan sebagainya. Seperti yang dibahas dalam komentar, lebih baik menunggu notifikasi perubahan papan klip.
Peter Cordes
@dessert: Jika saya tahu jawabannya, saya akan melakukannya. Saya hanya menyarankan menyebutkan dalam jawaban Anda bahwa bangun setiap 0,2 detik masih tidak dianggap sebagai desain yang baik , dan mencari pendekatan non-polling akan jauh lebih baik. Tetapi untuk peretasan sekali pakai yang hanya akan berjalan pada satu komputer, yakin itu tidak mengerikan, dan mungkin cukup baik.
Peter Cordes
26

Saya akhirnya membuatnya bekerja tanpa loop. Ini kodenya:

Saya harus menginstal beberapa modul: 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()

jangan ragu untuk memilih solusi yang cocok untuk Anda.

dmx
sumber
Oooh ... Kenapa kamu meminta clip.wait_for_text()dua kali?
wizzwizz4
@ wizzwizz4 Anda benar, saya mengedit ... tank
dmx
@ wizzwizz4 Tidak semua orang menyalin dua kali hanya untuk memastikan?
Michael Frank
16

Anda menjalankannya dalam satu while True:lingkaran! Itu berarti bahwa CPU secara konstan menjalankan loop Anda. Cukup tambahkan jeda kecil di sana dan Anda akan melihat penurunan penggunaan CPU dengan cepat:

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

Saya tertarik dengan proyek ini sehingga menulis skrip bash untuk mereka yang lebih nyaman di lingkungan itu:

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

Itu memang membutuhkan xclippaket Xorg :

sudo apt install xclip

Ini membuang konten clipboard ke layar menggunakan catperintah. Jika Anda ingin hard copy ganti catdengan lpdan tentukan nama printer Anda, orientasi dan mungkin opsi "fit to page".

Anda akan melihat sedikit lag ke layar karena saya memilih sleep 1.0yang tidak akan terlihat dengan printer dan masih lebih cepat daripada orang dapat menyorot teks dan menggunakan Ctrl+ C.

Jika Anda menyalin teks yang disorot sama persis ke clipboard itu tidak memicu perbedaan. Satu huruf kurang lebih akan memicu respons.

WinEunuuchs2Unix
sumber