我正在创建一个脚本来判断我的一些计算机的状态,但注意到随着时间的推移,Tkinter窗口正在积累越来越多的资源.有什么办法可以解决这个问题吗?

import subprocess
import time
import tkinter as tk
import threading
import gc

ip_addresses = ["192.168.1.83", "192.168.1.93", "192.168.1.93", "192.168.1.92", "192.168.1.95", "192.168.1.103", "192.168.1.105"]
i= 0
if i == 0:
    root = tk.Tk()
    root.title("Online")
    root.geometry("500x300")
    i+1

label_texts = [f"{ip_address} -> unknown" for ip_address in ip_addresses]
labels = [tk.Label(root, text=label_text, font=("Arial", 16), fg="#FF0000") for label_text in label_texts]
for i, label in enumerate(labels):
    label.pack(padx=10, pady=5)

def check_ip_status(ip_address, label):
    try:
        subprocess.check_output(f"ping {ip_address} -n 1", shell=True, timeout=5)
        label.config(text=f"{ip_address} -> online", fg="#00FF00") # Green
    except subprocess.CalledProcessError:
        label.config(text=f"{ip_address} -> offline", fg="#FF0000") # Red
    except subprocess.TimeoutExpired:
        label.config(text=f"{ip_address} -> offline (timeout)", fg="#FFA500") # Orange

def check_all_ip_statuses():
    processes = []
    for i, ip_address in enumerate(ip_addresses):
        label = labels[i]
        process = subprocess.Popen(f"ping {ip_address} -t", shell=True, stdout=subprocess.DEVNULL)
        processes.append(process)
        thread = threading.Thread(target=check_ip_status, args=(ip_address, label))
        thread.start()

    root.after(5000, check_all_ip_statuses) 
    gc.collect() 

    # Close all subprocesses
    for process in processes:
        process.kill()
        process.communicate()

check_all_ip_statuses()
root.mainloop()

我试图强迫垃圾收集器,终止所有进程,并偶尔清除标签,但没有什么能阻止他们囤积越来越多的内存

-------------Update---------

我已将子流程调用更改为pythonping

import pythonping
import time
import tkinter as tk
import threading
import gc

ip_addresses = ["192.168.1.83", "192.168.1.85", "192.168.1.93", "192.168.1.92", "192.168.1.95", "192.168.1.103", "192.168.1.105"]

i= 0
if i == 0:
    root = tk.Tk()
    root.title("Online")
    root.geometry("500x300")
    i+1

def create_labels():
    global labels
    labels = [tk.Label(root, text=f"{ip_address} -> unknown", font=("Arial", 16), fg="#FF0000") for ip_address in ip_addresses]
    for label in labels:
        label.pack(padx=10, pady=5)

def check_ip_status(ip_address, label):
    response = pythonping.ping(ip_address, count=1, timeout=5)
    if response.success():
        label.config(text=f"{ip_address} -> online", fg="#00FF00") # Green
    else:
        label.config(text=f"{ip_address} -> offline", fg="#FF0000") # Red

def check_all_ip_statuses():
    for i, ip_address in enumerate(ip_addresses):
        label = labels[i]
        thread = threading.Thread(target=check_ip_status, args=(ip_address, label))
        thread.start()

    gc.collect() 
    root.after(1000, check_all_ip_statuses) 

create_labels()
check_all_ip_statuses()
root.mainloop()

推荐答案

我试着找出为什么你的版本会填满内存,但我还不知道. 现在,我不知道如何使用所有的内存分析工具,以一种实用的方式在您的源代码中找到罪魁祸首.

因此,我创建了您的应用程序的另一个版本,就像我使用面向对象方法来完成它一样.

import sys
import threading
import time
import tkinter

import pythonping


class PingHost(threading.Thread):
    def __init__(self, ip, idx):
        super().__init__()
        self.daemon = True
        self.start_time = time.time()
        self.ip = ip
        self.idx = idx
        self.message = ''
        self.success = False

    def run(self) -> None:
        result = pythonping.ping(self.ip, count=1, timeout=5)
        if result.success():
            self.message = f'{self.ip} -> online'
            self.success = True
        else:
            self.message = f'{self.ip} -> offline'
            self.success = False


class App(tkinter.Frame):
    IP_ADDRESSES = [
        '192.168.80.101', '192.168.80.111', '192.168.80.123', '192.168.80.124', '192.168.80.125', '192.168.80.126',
        '192.168.80.127', '192.168.80.128'
    ]
    COLOR_ONLINE = '#00FF00'
    COLOR_OFFLINE = '#FF0000'
    FONT = ('Arial', 16)
    PING_THROTTLE = 10  # delay until a ping thread restarts

    def __init__(self, tk_root: tkinter.Tk):
        super().__init__(tk_root)
        self.root = tk_root
        self.root.protocol('WM_DELETE_WINDOW', self._on_quit)

        self.labels: [tkinter.Label] = []
        self.procs: [threading.Thread] = []

        self._create_widgets()

        self._ping_all_ips()
        self._monitor_procs()

    def _create_widgets(self):
        for ip in self.IP_ADDRESSES:
            string = f'{ip} -> unknown'
            label = tkinter.Label(self.root, text=string, fg=self.COLOR_OFFLINE, font=self.FONT)
            label.pack()
            self.labels.append(label)

    def _ping_all_ips(self):
        for idx, ip in enumerate(self.IP_ADDRESSES):
            self._start_ping_proc(ip, idx)

    def _start_ping_proc(self, ip, idx):
        ping_proc = PingHost(ip, idx)
        ping_proc.start()
        self.procs.append(ping_proc)

    def _monitor_procs(self):
        proc: PingHost
        for proc in self.procs:
            age = time.time() - proc.start_time

            if proc.is_alive():
                continue

            if age < self.PING_THROTTLE:
                self._update_labels(proc)
                continue

            self._update_labels(proc)
            self.procs.remove(proc)
            self._start_ping_proc(proc.ip, proc.idx)
        self.root.after(1000, self._monitor_procs)

    def _update_labels(self, proc):
        if "online" in proc.message:
            self.labels[proc.idx].configure(text=proc.message, fg=self.COLOR_ONLINE)
        else:
            self.labels[proc.idx].configure(text=proc.message, fg=self.COLOR_OFFLINE)

    def _on_quit(self):
        self.root.quit()
        sys.exit()


if __name__ == '__main__':
    root = tkinter.Tk()
    root.title('oop threading test')
    root.geometry('400x400')
    app = App(root)
    root.mainloop()

它昨天运行了一整晚,内存一直在12MB左右 我有很多理论来解释为什么这个能用而你的不能,但我不能在ATM上证明任何一个.

因此,如果有人能澄清这一点,我们将非常感激.

如果我找到更多,我会更新的.

Python相关问答推荐

如何推迟对没有公钥的视图/表的反射?

预期LP_c_Short实例而不是_ctyles.PyCStructType

Python中的锁定类和线程以实现dict移动

将嵌套列表的字典转换为数据框中的行

按 struct 值对Polars列表[struct[]]排序

Polars -转换为PL后无法计算熵.列表

Numpy索引argsorted使用integer数组,同时保留排序顺序

具有2D功能的Python十六进制图

收件箱转换错误- polars.exceptions. ComputeHelp- pandera(0.19.0b3)带有polars

PyQt5如何将pyuic 5生成的Python类添加到QStackedWidget中?

如何才能知道Python中2列表中的巧合.顺序很重要,但当1个失败时,其余的不应该失败或是0巧合

当多个值具有相同模式时返回空

如何避免Chained when/then分配中的Mypy不兼容类型警告?

按列分区,按另一列排序

OR—Tools中CP—SAT求解器的IntVar设置值

如何在Python中找到线性依赖mod 2

如何在Python中获取`Genericums`超级类型?

如何在Pyplot表中舍入值

基于多个数组的多个条件将值添加到numpy数组

使用Openpyxl从Excel中的折线图更改图表样式