ทำไมสคริปต์ไพ ธ อนนี้จึงทำงานในพื้นหลังที่ใช้ CPU 100%?


22

ฉันต้องการเรียกใช้สคริปต์หลามแบบง่าย ๆ ในพื้นหลังที่อ่านข้อความจากคลิปบอร์ดและพิมพ์ออกมา นี่คือรหัสของฉัน

#!/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
@ ของหวานฉันไม่เคยทำใน python มาก่อน แต่นี่น่าจะเป็นวิธีแก้ปัญหาของ GTK: stackoverflow.com/a/25961646/985296 (ไม่ได้กล่าวถึงการพึ่งพาแพลตฟอร์มใด ๆ )
ฟาน

@ jpmc26 และของหวานดูเหมือนว่าจะเป็นการสนทนาเมตาดาต้า เป็นความคิดที่ดีที่จะลบล้างขอบเขตนี้
เสา

1
@dessert เปิดเมตาดาต้าหากคุณและ JPMC ต้องการที่จะพูดคุยว่านี่เป็นหัวข้อเปิด / ปิด โปรดอย่าใช้ความคิดเห็นสำหรับข้อโต้แย้งนี้ (การล้างข้อมูลความคิดเห็นเสร็จสมบูรณ์หัวข้อถูกล็อคเป็นเวลาหนึ่งสัปดาห์เพื่อรอการอภิปราย Meta ของคุณ แต่เพื่อหยุดการโต้แย้งความคิดเห็น)
Thomas Ward

คำตอบ:


44

คุณลืมการวนรอบtime.sleep()ของคุณwhileตามคำตอบของ SO sleep สำหรับ 0.2s นี้เป็นการประนีประนอมที่ดีระหว่างความถี่การสำรวจและการโหลด CPU:

import time

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

การตรวจดูคลิปบอร์ดทุก ๆ 0.2 วินาทีนั้นบ่อยครั้งพอ หากคุณต้องการให้โหลด CPU น้อยลงคุณสามารถเพิ่มค่านี้ได้ - ผู้ใช้เพียงไม่กี่คนที่เปลี่ยนเนื้อหาของคลิปบอร์ดจากที่หนึ่งไปยังอีกที่หนึ่ง

โปรดทราบว่าโดยทั่วไปการสำรวจความคิดเห็นในวงบ่อยเท่าที่ไม่ถือว่าการออกแบบที่ดี แนวทางที่ดีกว่าคือการดำเนินการกับเหตุการณ์ของการเปลี่ยนแปลงเนื้อหาของคลิปบอร์ดตัวอย่างสำหรับ GTK สามารถพบได้ในคำตอบ SOนี้

อ่านเพิ่มเติม


3
คุณสามารถทำให้ช่วงเวลาสลีปสั้นลงโดยไม่กระทบกับเวลา CPU ที่ใช้จริง ๆ ฉันพบบน 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%
Floris

6
การสำรวจยังคงแย่อยู่เพราะมันจะทำให้กระบวนการนี้สร้างมลภาวะแคชของ CPU และต่อไปเรื่อย ๆ ตามที่กล่าวไว้ในความคิดเห็นดีกว่ามากที่จะรอการแจ้งเตือนการเปลี่ยนแปลงคลิปบอร์ด
Peter Cordes

@ ขนมหวาน: ถ้าฉันรู้คำตอบฉันจะ ผมขอแนะนำให้เพียงการกล่าวขวัญในคำตอบของคุณที่ตื่นขึ้นมาทุก 0.2 วินาทียังคงไม่ถือว่าเป็นสิ่งที่ดีการออกแบบและกำลังมองหาวิธีการที่ไม่ลงคะแนนเลือกตั้งจะดีกว่ามาก แต่สำหรับแฮ็คแบบครั้งเดียวซึ่งจะทำงานบนคอมพิวเตอร์เครื่องเดียวเท่านั้นตรวจสอบให้แน่ใจว่ามันไม่ได้น่ากลัวและอาจดีพอ
Peter Cordes

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()

อย่าลังเลที่จะเลือกวิธีแก้ปัญหาที่เหมาะกับคุณ


Oooh …ทำไมคุณถึงร้องขอclip.wait_for_text()สองครั้ง
wizzwizz4

@ wizzwizz4 ถูกต้องฉันแก้ไข ... รถถัง
dmx

@ wizzwizz4 ไม่สำเนาทุกคนเป็นครั้งที่สองเพียงเพื่อให้แน่ใจว่า?
Michael Frank

16

คุณกำลังทำสิ่งนี้อยู่ในwhile True:วงจร! นั่นหมายความว่า CPU ทำงานวนรอบของคุณอย่างต่อเนื่อง เพียงเพิ่มการหยุดชั่วคราวเล็กน้อยที่นั่นและคุณจะเห็นการใช้งาน CPU ลดลงอย่างรวดเร็ว:

#!/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ที่จะสังเกตกับเครื่องพิมพ์และยังคงเร็วกว่าคนสามารถเน้นข้อความและการใช้งาน+CtrlC

หากคุณคัดลอกข้อความที่เน้นสีเดียวกันไปยังคลิปบอร์ดมันจะไม่ทำให้เกิดความแตกต่าง จดหมายหนึ่งฉบับมากหรือน้อยจะทำให้เกิดการตอบกลับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.