当前位置: 首页 > 知识库问答 >
问题:

Tcl_异步删除多线程Python错误

后学
2023-03-14

我听说Python中的线程不容易处理,而且它们与tkinter的关系更加复杂。

我有以下问题。我有两个类,一个用于GUI,另一个用于无限进程(我必须同时使用这两个类)。首先,我启动GUI类,然后启动无限进程类。我希望当您关闭GUI时,它也会完成无限过程,程序也会结束。

代码的简化版本如下所示:

import time, threading
from tkinter import *
from tkinter import messagebox

class Interface(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.attrib1 = "Attrib from Interface class"

    def run(self): 
        #Main Window
        self.mainWindow = Tk()
        self.mainWindow.geometry("200x200")
        self.mainWindow.title("My GUI Title")
        self.mainWindow.protocol("WM_DELETE_WINDOW", self.quit)
        #Label
        lbCommand = Label(self.mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20)
        #Start
        self.mainWindow.mainloop()

    #The Interface class contains methods that use attributes from itself and attributes from Process class.
    def method1(self): 
        print(self.attrib1)
        print(SecondThread.attrib2)

    def quit(self):
        if messagebox.askyesno('App','Are you sure you want to quit?'):
            #In order to use quit function, mainWindow MUST BE an attribute of Interface. 
            self.mainWindow.destroy()
            self.mainWindow.quit()  

class Process(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.attrib2 = "Attrib from Process class"

    def run(self):
        global finish
        while not finish:
            print("Proceso infinito")
            #Inside the infinite process a method from Interface class is used.
            GUI.method1()
            time.sleep(3)

finish = False  
#Starts the GUI
GUI = Interface()
GUI.start()
#Starts the infinity process
SecondThread = Process()
SecondThread.start()    
#Waits until GUI is closed
GUI.join()
print("When GUI is closed this message appears")
#When GUI is closed we set finish to True, so SecondThread will be closed.
finish = True
#After all the program should finish but it raises the error: Tcl_AsyncDelete: async handler deleted by the wrong thread

谢谢你的帮助!

共有2个答案

齐高寒
2023-03-14

我使用垃圾收集进行了粗略的修改。

import time, threading, gc
from tkinter import *
from tkinter import messagebox

class Interface(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.attrib1 = "Attrib from Interface class"

    def run(self):
        #Main Window
        self.mainWindow = Tk()
        self.mainWindow.geometry("200x200")
        self.mainWindow.title("My GUI Title")
        self.mainWindow.protocol("WM_DELETE_WINDOW", self.quit)
        #Label
        lbCommand = Label(self.mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20)
        #Start
        self.mainWindow.mainloop()

    #The Interface class contains methods that use attributes from itself and attributes from Process class.
    def method1(self):
        print(self.attrib1)
        print(SecondThread.attrib2)

    def quit(self):
        global finish
        if messagebox.askyesno('App','Are you sure you want to quit?'):
            #In order to use quit function, mainWindow MUST BE an attribute of Interface.
            self.mainWindow.destroy()
            del self.mainWindow
            gc.collect()
            finish = True

class Process(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.attrib2 = "Attrib from Process class"

    def run(self):
        global finish
        while not finish:
            print("Proceso infinito")
            #Inside the infinite process a method from Interface class is used.
            GUI.method1()
            time.sleep(3)

finish = False
#Starts the GUI
GUI = Interface()
GUI.start()
#Starts the infinity process
SecondThread = Process()
SecondThread.start()
#Waits until GUI is closed
GUI.join()
#print("When GUI is closed this message appears")
#When GUI is closed we set finish to True, so SecondThread will be closed.
#finish = True
涂泰平
2023-03-14

出现这种情况是因为您在线程上创建了Tk主窗口,而您没有在进程主线程上运行UI。退出进程时,将从进程主线程执行清理。对于您的示例,最简单的解决方案是在主线程(进程默认线程)上创建UI,并且仅使用另一个线程执行辅助任务。如果您的实际应用程序无法在主线程上创建UI,则需要研究从自己的线程终止Tk。删除Tcl解释器可能会为您做到这一点。

我修改了示例代码,以显示将UI保留在主线程上可以避免此错误消息。因为您希望在UI创建后但在运行之前创建辅助角色,所以一旦Tk主循环运行,我们可以使用Tk后方法启动辅助角色。

import time, threading
from tkinter import *
from tkinter import messagebox

class Interface:
    def __init__(self):
        #threading.Thread.__init__(self)
        self.attrib1 = "Attrib from Interface class"
        #Main Window
        self.mainWindow = Tk()
        self.mainWindow.geometry("200x200")
        self.mainWindow.title("My GUI Title")
        self.mainWindow.protocol("WM_DELETE_WINDOW", self.quit)
        #Label
        lbCommand = Label(self.mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20)

    #def run(self): 

    def start(self): #Start
        self.mainWindow.mainloop()

    #The Interface class contains methods that use attributes from itself and attributes from Process class.
    def method1(self): 
        print(self.attrib1)
        print(SecondThread.attrib2)

    def quit(self):
        if messagebox.askyesno('App','Are you sure you want to quit?'):
            #In order to use quit function, mainWindow MUST BE an attribute of Interface. 
            self.mainWindow.destroy()
            self.mainWindow.quit()  

class Process(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.attrib2 = "Attrib from Process class"

    def run(self):
        global finish
        while not finish:
            print("Proceso infinito")
            #Inside the infinite process a method from Interface class is used.
            GUI.method1()
            time.sleep(3)

finish = False
#Starts the GUI

GUI = Interface()
#Starts the infinity process
SecondThread = Process()
GUI.mainWindow.after(50, SecondThread.start)   
#Waits until GUI is closed
GUI.start()
#GUI.join()
print("When GUI is closed this message appears")
#When GUI is closed we set finish to True, so SecondThread will be closed.
finish = True
#After all the program should finish but it raises the error: Tcl_AsyncDelete: async handler deleted by the wrong thread
 类似资料:
  • 问题内容: 我发现在Python 3.4中,用于多处理/线程的库很少:多处理vs线程与asyncio。 但是我不知道使用哪个,或者是“推荐的”。他们做的是同一件事还是不同?如果是这样,则将哪一个用于什么?我想编写一个在计算机上使用多核的程序。但是我不知道我应该学习哪个图书馆。 问题答案: 它们旨在(略有)不同的目的和/或要求。CPython(典型的主线Python实现)仍然具有全局解释器锁,因此多

  • 本文向大家介绍python并发编程之多进程、多线程、异步和协程详解,包括了python并发编程之多进程、多线程、异步和协程详解的使用技巧和注意事项,需要的朋友参考一下 最近学习python并发,于是对多进程、多线程、异步和协程做了个总结。 一、多线程 多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行。即使是单CPU的计算机,也可以通过不停地在不同

  • 我在StackOverflow的职业生涯中有一个第一个问题。我希望是你帮我。 发生了什么:

  • 我有一个spring boot微服务,我们在其中调用多个服务(比如服务a和服务B)。我试图根据某些条件在多个线程上异步调用这两个服务,一旦处理完成,我想合并服务A和服务B的响应。 我知道我们可以使用@Async异步运行一个进程,并使用ExecutorService为一个服务启动多个线程。 但是我不确定如何把所有的东西放在一起。所以在这里寻找任何建议? 我知道这在上面主要是理论上解释的,但我尝试了跟

  • 我正在使用来处理通过文件的大量记录。每一行都是一条记录,我将每一行传递给单独的线程进行处理,问题是我必须收集这些处理过的记录以及在处理记录时生成的更多数据,然后在最后的数据收集上应用一些业务逻辑。我将一个通用的传递给所有线程来填充已处理的数据,当我通过visualVM调试它时,我发现(屏幕截图如下)这些线程在等待中花费的时间比在运行中花费的时间多。我想这是因为一个线程在写入时获得了锁。 有没有一种

  • 线程中使用 java.lang.Runnable 如果用户在代码中通过 java.lang.Runnable 新启动了线程或者采用了线程池去异步地处理一些业务,那么需要将 SOFATracer 日志上下文从父线程传递到子线程中去,SOFATracer 提供的 com.alipay.common.tracer.core.async.SofaTracerRunnable 默认完成了此操作,大家可以按照