Tại sao tập lệnh python này chạy trong nền tiêu thụ CPU 100%?


22

Tôi muốn chạy một kịch bản python đơn giản trong nền đọc văn bản từ bảng ghi tạm và in nó ra. Đây là mã của tôi.

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

Điều này hoạt động như mong đợi nhưng nó tiêu tốn quá nhiều CPU (100% CPU).

Làm thế nào tôi có thể làm cho nó hoạt động chính xác mà không tiêu thụ nhiều như vậy?


26
Nếu tất cả được hỗ trợ bởi khung bạn đang sử dụng, hãy sử dụng mã dựa trên sự kiện để phát hiện các thay đổi trong bảng tạm thay vì vòng lặp. Có một sự khác biệt giữa việc lấy bảng tạm liên tục cho đến khi nó thay đổi hoặc lắng nghe hệ thống cho bạn biết rằng nó đã thay đổi.
stefan

6
@dPlay Tôi chưa bao giờ thực hiện nó trong python, nhưng đây dường như là một giải pháp với GTK: stackoverflow.com/a/25961646/985296 (không đề cập đến bất kỳ sự phụ thuộc nền tảng nào).
stefan

@ jpmc26 & tráng miệng Trông giống như một cuộc thảo luận về meta, cứ thoải mái đưa nó lên đó. Chắc chắn là một ý tưởng tốt để làm cho điều này rõ ràng cho phạm vi .
Cột

1
@d PLAY Mở một chuỗi meta nếu bạn và JPMC muốn thảo luận xem đây có phải là chủ đề bật / tắt hay không. Xin vui lòng không sử dụng ý kiến ​​cho lập luận này. (Hoàn tất quá trình dọn dẹp nhận xét, chủ đề bị khóa trong một tuần trong khi chờ thảo luận Meta của bạn nhưng cũng dừng cuộc tranh luận bình luận)
Thomas Ward

Câu trả lời:


44

Bạn đã quên time.sleep()trong whilevòng lặp của mình , theo câu trả lời này trên SO ngủ trong 0,2 giây là một sự thỏa hiệp tốt giữa tần số bỏ phiếu và tải CPU:

import time

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

Kiểm tra clipboard trong mỗi 0,2 giây dường như dễ dàng thường xuyên; nếu bạn muốn tải CPU ít hơn, bạn thậm chí có thể tăng giá trị này - một vài người dùng thay đổi nội dung clipboard từ giây này sang giây khác.

Lưu ý rằng trong bỏ phiếu chung trong một vòng lặp thường xuyên như vậy không được coi là thiết kế tốt. Một cách tiếp cận tốt hơn sẽ là hành động trong trường hợp thay đổi nội dung clipboard, một ví dụ cho GTK có thể được tìm thấy trong câu trả lời SO này .

đọc thêm


3
Bạn có thể làm cho khoảng thời gian ngủ ngắn hơn mà không thực sự ảnh hưởng đến thời gian CPU được sử dụng. Tôi tìm thấy trên máy Mac của mình: 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
Việc bỏ phiếu vẫn còn tệ bởi vì nó tiếp tục đánh thức quá trình này gây ô nhiễm bộ nhớ CPU, v.v. Như đã thảo luận trong các bình luận tốt hơn nhiều để chờ thông báo về việc thay đổi clipboard.
Peter Cordes

@dPlay: Nếu tôi biết câu trả lời, tôi sẽ. Tôi chỉ đề nghị đề cập đến trong câu trả lời của bạn rằng cứ sau 0,2 giây thức dậy vẫn không được coi là một thiết kế tốt và tìm kiếm một phương pháp không bỏ phiếu sẽ tốt hơn nhiều. Nhưng đối với một bản hack một lần chỉ chạy trên một máy tính, chắc chắn nó không khủng khiếp và có lẽ là đủ tốt.
Peter Cordes

26

Cuối cùng tôi làm cho nó hoạt động một vòng lặp không có. Đây là mã:

Tôi đã phải cài đặt một vài mô-đun: 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()

hãy chọn giải pháp phù hợp với bạn.


Tại sao bạn yêu cầu clip.wait_for_text()hai lần?
wizzwizz4

@ wizzwizz4 bạn nói đúng Tôi đã chỉnh sửa ... xe tăng
dmx

@ wizzwizz4 Không phải ai cũng sao chép hai lần chỉ để đảm bảo sao?
Michael Frank

16

Bạn đang chạy điều trong một while True:vòng lặp! Điều đó có nghĩa là CPU liên tục chạy vòng lặp của bạn. Chỉ cần thêm một khoảng dừng nhỏ ở đó và bạn sẽ thấy việc sử dụng CPU giảm nhanh chóng:

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

Tôi bị thu hút bởi dự án này nên đã viết một kịch bản bash cho những người thoải mái hơn trong môi trường đó:

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

Nó yêu cầu xclipgói của Xorg :

sudo apt install xclip

Đó là đổ nội dung clipboard vào màn hình bằng catlệnh. Nếu bạn muốn sao chép cứng thay thế catbằng lpvà chỉ định tên máy in, hướng và có thể tùy chọn "phù hợp với trang".

Bạn sẽ thấy một chút độ trễ màn hình bởi vì tôi chọn sleep 1.0sẽ không thể nhận thấy bằng máy in và vẫn nhanh hơn mọi người có thể đánh dấu văn bản và sử dụng Ctrl+ C.

Nếu bạn sao chép chính xác văn bản được tô sáng vào bảng tạm thì nó sẽ không gây ra sự khác biệt. Một chữ cái ít nhiều sẽ kích hoạt một phản ứng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.