Чому цей скрипт python працює у фоновому режимі, що споживає 100% процесора?


22

Я хочу запустити простий скрипт python у фоновому режимі, який читає текст із буфера обміну і роздруковує його. Ось мій код.

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

Це працює як очікувалося, але для цього витрачається занадто багато CPU (100% CPU).

Як я можу змусити його працювати правильно, не витрачаючи так багато?


26
Якщо це взагалі підтримується рамкою, яку ви використовуєте, використовуйте код на основі подій, щоб виявити зміни в буфері обміну, а не в циклі. Існує різниця між тим, щоб отримувати буфер обміну постійно, поки він не змінюється, або слухати систему, яка каже вам, що він змінився.
Стефан

6
@dessert Я ніколи не робив цього в python, але тут, здається, є рішення з GTK: stackoverflow.com/a/25961646/985296 (не згадується про будь-яку залежність від платформи).
Стефан

@ jpmc26 & десерт Виглядає як мета-дискусія, не соромтеся взяти її там. Безумовно, хороша ідея, щоб це було зрозуміло для сфери застосування .
Щогла

1
@dessert Відкрийте мета-нитку, якщо ви та JPMC хочете обговорити, чи це тема вмикання та вимкнення. Будь ласка, не використовуйте коментарі для цього аргументу. (Чистка коментарів завершена. Тема заблокована на тиждень до очікування вашої мета-дискусії, а також для припинення аргументації коментарів)
Thomas Ward

Відповіді:


44

Ви забули time.sleep()в своєму whileциклі, відповідно до цієї відповіді про стан сну на 0,2 секунди - це хороший компроміс між частотою опитування та завантаженням процесора:

import time

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

Перевірка буфера обміну кожні 0,2 секунди здається легко досить часто; якщо ви хочете менше завантаження процесора, ви можете навіть збільшити це значення - мало користувачів змінюють вміст буфера обміну з однієї секунди на іншу.

Зауважте, що загалом опитування в циклі так часто, що не вважається хорошим дизайном. Кращим підходом було б діяти у випадку зміни вмісту буфера обміну, приклад для GTK можна знайти у цій відповіді ТА .

Подальше читання


3
Ви можете зробити інтервал сну коротшим, не впливаючи на час процесора. Я знайшов на своєму Mac: 0,01 с: 69%, 0,02 с: 43%, 0,05 с: 25%, 0,1 с: 14%, 0,2 с: 7%. 0,5 с: 3%
Флоріс

6
Опитування все ще відстійне, оскільки воно продовжує пробуджувати цей процес, забруднюючи кеші процесора тощо. Як обговорюється в коментарях, набагато краще чекати сповіщення про зміну буфера обміну.
Пітер Кордес

@dessert: Якби я знав відповідь, я би. Я просто пропоную згадати у своїй відповіді, що прокидання кожні 0,2 секунди все ще не вважається хорошим дизайном, і шукати підхід, який не проводить опитування, було б набагато краще. Але для одноразового злому, який збирається запускати лише на одному комп’ютері, впевнений, що це не жахливо і, ймовірно, досить добре.
Пітер Кордес

26

Я нарешті змушую його працювати без циклу. Це код:

Мені довелося встановити кілька модулів: 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()

сміливо вибирайте рішення, яке підходить саме вам.


Ооо ... Чому ти просиш clip.wait_for_text()двічі?
wizzwizz4

@ wizzwizz4 ви праві, я відредагував ... танки
dmx

@ Wizzwizz4 чи не кожен екземпляр двічі просто , щоб бути впевненим?
Майкл Франк

16

Ви запускаєте річ у while True:циклі! Це означає, що процесор постійно працює у вашому циклі. Просто додайте туди невелику паузу, і ви побачите, що скорочення використання процесора скоротиться:

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

Мене цей проект заінтригував, тому написав баш-сценарій для тих, хто більш комфортний у цьому середовищі:

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

Для цього потрібен xclipпакет Xorg :

sudo apt install xclip

Це скидання вмісту буфера обміну на екран за допомогою catкоманди. Якщо ви хочете тверду копію замість заміни catз lpі вказати ім'я принтера, орієнтацію і , можливо , «підходить до сторінці» варіант.

Ви побачите трохи відставання на екрані, тому що я вибираю, sleep 1.0що було б непомітно для принтера, але все ж швидше, ніж люди можуть виділити текст та використовувати Ctrl+ C.

Якщо ви скопіюєте такий самий виділений текст у буфер обміну, це не викликає різниці. Одна чи інша літера викликає відповідь.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.