【问题标题】:Memory leak when using threads and tkinter使用线程和 tkinter 时的内存泄漏
【发布时间】:2026-02-01 15:15:01
【问题描述】:

我一直在研究这个“游戏事物”。它工作得很好,除了当我在没有完成游戏的情况下关闭 GUI 时,它会继续在后台运行,(就像它是内存泄漏一样,即使“真正的”内存泄漏不是那样工作的)。

这个游戏在两个线程上运行(或者理论上应该),一个用于 GUI,另一个用于游戏本身,经过一些研究,我发现我可以在我的根小部件上使用 .protocol() 方法来执行raise SystemExit 以确保在关闭 GUI 时终止所有线程。但它似乎不起作用,我不知道为什么。代码如下:

# -*- coding: UTF-8 -*-
from tkinter import Tk, Label, Entry, Button, W, E, END
from threading import Thread
from random import randint
class GUI(Thread):
    tentativas = []
    def __init__(self):
        Thread.__init__(Thread)
        self.start()
        self.valor = randint(0, 100)
        self.vidas = 6
        self.venceu = False
        self.entry, self.aux = -128, -128
        while self.vidas > 0:
            self.vidas -= 1
            while True:
                if self.entry != self.aux:
                    break
            self.aux = self.entry
            if self.entry == self.valor:
                self.txt01.config(text = "Congrats, you won!", fg = "green")
                self.venceu = True
                self.txt02.config(text = '')
                break
            elif self.entry > self.valor:
                self.txt01.config(text = 'Too big, try again.')
            else:
                self.txt01.config(text = 'Too small, try again.')
            self.txt02.config(text = str(self.vidas) + ' Chances restantes.')
        if self.venceu != True:
            self.txt01.config(text = 'You ran out of lives, game over!')
            self.txt02.config(text = 'The number was ' + str(self.valor) + '.')
    def run(self):
        self.root = Tk()
        self.root.title("Lottery")
        self.txt00 = Label(self.root, text = "Welcome, insert a number ranging from 0 to 100:")
        self.txt00.grid(sticky = W, columnspan = 4)
        self.txt01 = Label(self.root, text = " ")
        self.txt01.grid(row = 1, column = 0, columnspan = 4, sticky = W)
        self.txt02 = Label(self.root, text ="6 Tentativas restantes.")
        self.txt02.grid(row = 4, columnspan = 2, sticky = E)
        self.inp00 = Entry(self.root)
        self.inp00.grid(row = 2,columnspan = 2,column = 1,sticky = W)
        self.but00 = Button(self.root, text = "Try!", command = self.chutar)
        self.root.bind("<Return>", self.chutar)
        self.but00.grid(row = 2, column = 3)
        self.root.protocol("WM_DELETE_WINDOW", self.killGUI)
        self.root.mainloop()
    def chutar(self, args = None):
        self.pular = True
        try:
            self.chute = int(self.inp00.get())
        except ValueError:
            self.txt01.config(text = "Invalid entry, try again!", fg = "red")
            self.pular = False
        finally:
            self.inp00.delete(0, END)
        if self.pular:
            if self.chute in range(101) and self.chute not in self.tentativas:
                self.entry = self.chute
                self.tentativas.append(self.entry)    
            else:
                self.var = "Invalid entry, try again!"
                self.txt01.config(text = self.var, fg = "red")
    def killGUI(self):
        raise SystemExit
k = GUI()

我真的不知道为什么“killGUI”功能不起作用,请帮助我!

【问题讨论】:

    标签: multithreading python-3.x memory-leaks tkinter


    【解决方案1】:

    (据我所知,Tkinter 不是线程安全的。这可能会导致这个问题。所以在 Tkinter 中使用线程并不是一个好主意。我什至不确定你是否真的需要多线程。)

    编辑:好像你只是用这个杀死你的子线程,主线程仍在运行。

    但要解决您的问题,一种方法是强制“杀死”整个进程树。您所需要的只是您的脚本 pid 和一个子进程函数。在您的 killGUI 中尝试此代码:

    def killGUI(self):
        try:
            subprocess.call(['taskkill', '/F', '/T', '/PID', str(os.getpid())])
            print("Process killed: %s " % str(os.getpid()))
        except Exception as ex:
            print(ex)
    

    这肯定会杀死你的线程。

    【讨论】: