Skip to main content
 首页 » 编程设计

python之如何使用多线程执行子进程

2025年05月04日20虾米姐

这个程序在一个小 Canvas 上工作并显示服务器延迟,但是因为程序需要时间来 ping 服务器并显示 ping def display():,所以不能拖动window class WindowDraggable():,直到子进程完成,因此拖动窗口时有延迟。是否可以使用多线程解决此延迟问题,以便可以平滑地拖动窗口?

from tkinter import * 
from PIL import ImageTk, Image 
import subprocess 
import _thread 
 
host = "141.101.115.212" #host IP address 
 
root = Tk() 
root.overrideredirect(1) 
im = Image.open("image.png") 
width, height = im.size 
canvas = Canvas(root, width=width, height=height) 
canvas.pack() 
image = ImageTk.PhotoImage(file="image.png") 
canvas.create_image(0, 0, image=image, anchor=NW) 
text = canvas.create_text(125, 75, anchor=CENTER) 
 
def display(): 
    global text 
    #Launches 'command' windowless and waits until finished; finds ping 
    suinfo = subprocess.STARTUPINFO() 
    suinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 
    x = subprocess.Popen(["ping.exe", "141.101.115.212"], stdout=subprocess.PIPE, startupinfo=suinfo) 
    #find latency with regex 
    x = str(x.communicate()[0]) 
    lhs, rhs = x.split("Average = ") 
    lhs, rhs = rhs.split("\\", 1) 
    lhs, rhs = lhs.split("m") 
    if int(lhs) > 999: 
        lhs = "999" + "ms" 
    latency = lhs 
    canvas.itemconfig(text, text=latency, width=width) 
    canvas.itemconfig(text, font=("courier", 25, "bold")) 
    canvas.itemconfig(text, fill="white") 
    root.after(1000, display) 
 
 
class WindowDraggable(): 
 
    def __init__(self, label): 
        self.label = label 
        label.bind('<ButtonPress-1>', self.StartMove) 
        label.bind('<ButtonRelease-1>', self.StopMove) 
        label.bind('<B1-Motion>', self.OnMotion) 
 
    def StartMove(self, event): 
        self.x = event.x 
        self.y = event.y 
 
    def StopMove(self, event): 
        self.x = None 
        self.y = None 
 
    def OnMotion(self,event): 
        x = (event.x_root - self.x - self.label.winfo_rootx() + self.label.winfo_rootx()) 
        y = (event.y_root - self.y - self.label.winfo_rooty() + self.label.winfo_rooty()) 
        root.geometry("+%s+%s" % (x, y)) 
 
label = Label(root, text='drag me') 
WindowDraggable(label) 
label.pack() 
#_thread.start_new_thread( print_time, ("Thread-2", 4, ) ) 
root.after(0, display()) 
root.mainloop() 

请您参考如下方法:

与其尝试对抗 Tkinter 的内置循环/线程,不如使用它:

def wait_for_it(proc): 
    proc.poll() 
    if proc.returncode is None:                      # subprocess hasn't finished yet 
        root.after(100, lambda: wait_for_it(proc))   # register a callback for 100ms 
    else: 
        display(proc.communicate()[0]) 
 
 
def display(x): 
    lhs, rhs = x.split("Average = ") 
    # the rest of your code goes here... 
 
# instead of root.after(0, display) 
wait_for_it(subprocess.Popen(['ping', 'google.com'])) 

顺便说一句,我强烈建议将您的代码粘贴到 Code Review Stack Exchange 以获得一些样式指针并帮助简化它。