Python GUI 多处理并且仍在冻结



我正在使用TKinter为python程序im制作绘制一个GUI,我让它在大约200ms时更新,但是当程序查询数据时,它会锁定程序,因为它需要一秒钟才能获取数据。我尝试将其写入多处理中,以便每个查询都是自己的进程,并且只与全局变量共享信息,因为我的程序是一个使用 wmi 获取性能数据的实时程序。至少到目前为止我是这样。不是最终目标,只是开始。因此,如果您能帮助我弄清楚为什么即使使用多处理,如果我在屏幕上拖动应用程序时查询信息,它也会冻结一秒钟。

import wmi
import time
import Tkinter as tk
from multiprocessing import cpu_count
import Image
from PIL import ImageTk
from Tkinter import Button, Label
import threading
from multiprocessing import Process, Value, Array
window = Tk();
global pct_in_use
global available_mbytes
global utilization
global hours_up
a= 0 
b=0    

def build_labels(gui, string):
    var = StringVar()
    label = Label( gui, textvariable=var, relief=RAISED )
    var.set(string)
    return label
def get_uptime():
    global hours_up
    c = wmi.WMI()
    secs_up = int([uptime.SystemUpTime for uptime in c.Win32_PerfFormattedData_PerfOS_System()][0])
    hours_up = secs_up / 3600
    return hours_up
def get_cpu():
    global utilization
    c = wmi.WMI()
    utilizations = [cpu.LoadPercentage for cpu in c.Win32_Processor()]
    utilization = int(sum(utilizations) / len(utilizations))  # avg all cores/processors
    return utilization
def get_mem_mbytes():
    global available_mbytes
    c = wmi.WMI()
    available_mbytes = int([mem.AvailableMBytes for mem in c.Win32_PerfFormattedData_PerfOS_Memory()][0])
    return available_mbytes
def get_mem_pct():
    global pct_in_use
    c = wmi.WMI()
    pct_in_use = int([mem.PercentCommittedBytesInUse for mem in c.Win32_PerfFormattedData_PerfOS_Memory()][0])
    return pct_in_use
def Draw():
    global mem_per_lb
    global cpu_lb
    global up_time_lb
    global mb_used_lb
    mem_pct = 0
    mem_per_lb = tk.Label(text='Memory % ' + str(mem_pct))
    mem_per_lb.place(x=10, y=10)
    cpu = 0
    cpu_lb = tk.Label(text='CPU % ' + str(cpu))
    cpu_lb.place(x=10, y=30)
    mem_pct = 0
    up_time_lb = tk.Label(text='UP Time % ' + str(mem_pct))
    up_time_lb.place(x=10, y=50)
    mem_pct = 0
    mb_used_lb = tk.Label(text='Memory MB ' + str(mem_pct))
    mb_used_lb.place(x=10, y=70)    

def Refresher():
    global mem_per_lb
    global cpu_lb
    global up_time_lb
    global mb_used_lb
    mem_pct = get_mem_pct()
    cpu = get_cpu()
    up_time = get_uptime()
    mbused = get_mem_mbytes()
    window.wm_title('Vision' + time.asctime())
    mem_per_lb.configure(text='Memory % ' + str(pct_in_use))
    cpu_lb.configure(text='CPU ' + str(utilization))
    up_time_lb.configure(text='UP Time ' + str(hours_up))
    mb_used_lb.configure(text='Memory MB ' + str(available_mbytes))
    window.after(200, Refresher) # every second...
def draw_window():               #creates a window 
    window.geometry('704x528+100+100')
    image = Image.open('bg.jpg')     #gets image (also changes image size)
    image = image.resize((704, 528))
    imageFinal = ImageTk.PhotoImage(image)
    label = Label(window, image = imageFinal)   #creates label for image on window 
    label.pack()
    label.place(x = a, y = b)      #sets location of label/image using variables 'a' and 'b'
    Draw()
    Refresher()
    window.mainloop()
up_time_p = Process(target=get_uptime())
cpu_p = Process(target=get_cpu())
mb_p = Process(target=get_mem_mbytes())
pct_p = Process(target=get_mem_pct())
win_p = Process(target=draw_window())
up_time_p.start()
mb_p.start()
pct_p.start()
cpu_p.start()
win_p.start()
up_time_p = Process(target=get_uptime())
cpu_p = Process(target=get_cpu())
mb_p = Process(target=get_mem_mbytes())
pct_p = Process(target=get_mem_pct())
win_p = Process(target=draw_window())

我认为当您为流程提供目标时,您不应该包含括号。如果这样做,函数将在主线程中执行,无论这些函数返回什么,都将成为目标。

up_time_p = Process(target=get_uptime)
cpu_p = Process(target=get_cpu)
mb_p = Process(target=get_mem_mbytes)
pct_p = Process(target=get_mem_pct)
win_p = Process(target=draw_window)

根据 Kevin的回答,您在创建每个流程实例时调用函数。所以它们实际上都在主进程中运行。

但是,一旦解决了这个问题,您的"全局"变量就不会按预期工作。创建进程时,它会占用父进程内存的副本。对该内存的任何更改都不会在进程之间共享。

为了达到你想要的结果,你必须使用Python的线程库。不是多进程库。

线程与父进程共享相同的内存空间。这可能会导致自己的问题。虽然在您的情况下,您要更改的全局变量只是整数常量,所以应该没问题。

from threading import Thread
data_funcs = (
    get_uptime, 
    get_cpu, 
    get_mem_mbytes, 
    get_mem_pct, 
    draw_window
)
threads = [Thread(target=f) for f in data_funcs]
for t in threads:
    t.start()

是您应该使用的一般模式。然后,您必须找出一种在关闭主进程时杀死这些线程的方法,否则它将挂起。

最新更新