You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RuntimeError: 解释器关闭时无法创建新线程问题求助

问题:点击Reload按钮触发RuntimeError: can't create new thread at interpreter shutdown

在VSCode运行Python程序时,启动阶段客户端和站点加载正常,但点击加载完成后出现的「Reload clients」按钮重新加载客户端时,触发上述错误。同款程序在朋友的相同设备上可正常运行。

相关代码

import tkinter
from tkinter import ttk
import threading
import time

class Main:
    def __init__(self) -> None:
        
        # Variables to check if the progress bar is running (not crucial for the current issue)
        self.is_progress_bar_running = False
        self.is_change = False
        self.state = None
        self.client_loaded = False
        # Launching everything in parallel
        thread_client_list = threading.Thread(target=self.client_list) 
        thread_client_list.start()
        thread_get_sites = threading.Thread(target=self.get_sites)
        thread_get_sites.start()
        tkinter_start = threading.Thread(target=self.show_gui)
        tkinter_start.start()

    def client_list(self):
        """Find clients
        """

        time.sleep(3)
        
        self.client_loaded = True
        return

    def get_sites(self):
        """Find sites
        """

        time.sleep(3)

        return

    def start_progress_bar(self, direction):
        """Starts the loading bar until everything is loaded

        Args:
            direction (bool): True if the bar is moving to the right, False if the bar is moving to the left
        """
        if not self.is_progress_bar_running:
            self.is_progress_bar_running = True
            # If self.client_loaded
            if not isinstance(self.client_loading, ttk.Progressbar):
                self.state = None
                self.is_change = False
                
                self.client_loading_label["text"] = "Loading clients in progress..."
                self.client_loading.destroy()
                self.client_loading = ttk.Progressbar(self.general_info_frame, orient="horizontal", length=100, mode="indeterminate", takefocus=True, maximum=100, value=0)
                self.client_loading.grid(row=1,column=1,padx=20,pady=20)
                self.client_loaded = False
                # Restart loading clients and sites
                self.thread_client_list = threading.Thread(target=self.client_list) 
                self.thread_client_list.start()
                self.thread_get_sites = threading.Thread(target=self.get_sites)
                self.thread_get_sites.start()
            
            # If direction is True, move forward
            if direction:
                self.client_loading['value'] += 25
                # Change direction when reaching the end
                if self.client_loading['value'] + 25 > 100:
                    direction = False
                # Destroy the loading bar when everything is loaded
                if self.client_loaded:
                    if self.state == 3:
                        self.client_loading_label["text"] = "Error: no internet connection\nReload?"
                        self.client_loading.destroy()
                        self.client_loading = tkinter.Button(self.general_info_frame, text="Reload clients", command= lambda: self.start_progress_bar(True))
                        self.client_loading.grid(row=1,column=1,padx=20,pady=20)
                        self.is_progress_bar_running = False
                    else:
                        self.client_loading_label["text"] = "Clients loaded!\nReload?"
                        self.client_loading.destroy()
                        self.client_loading = tkinter.Button(self.general_info_frame, text="Reload clients", command= lambda: self.start_progress_bar(True))
                        self.client_loading.grid(row=1,column=1,padx=20,pady=20)
                        self.is_progress_bar_running = False
                # Otherwise, start again
                else:
                    self.is_progress_bar_running = False
                    self.window.after(400, lambda: self.start_progress_bar(direction))
            # Otherwise, move backward
            else:
                self.client_loading['value'] -= 25
                # Change direction when reaching the end
                if self.client_loading['value'] - 25 < 0:
                    direction = True
                # Destroy the loading bar when everything is loaded
                if self.client_loaded:
                    self.client_loading_label["text"] = "Clients loaded!\nReload?"
                    self.client_loading.destroy()
                    self.client_loading = tkinter.Button(self.general_info_frame, text="Reload clients", command= lambda: self.start_progress_bar(True))
                    self.client_loading.grid(row=1,column=1,padx=20,pady=20)
                    self.is_progress_bar_running = False
                # Otherwise, start again
                else:
                    self.is_progress_bar_running = False
                    self.window.after(400, lambda: self.start_progress_bar(direction))

    def show_gui(self):
        """Function that displays the entire interface
        """
        self.window = tkinter.Tk()
        self.window.title("Synchroteam Task Creation Form")

        self.frame = tkinter.Frame(self.window)
        self.frame.pack()

        # User information
        self.general_info_frame = tkinter.LabelFrame(self.frame, text="General Information")
        self.general_info_frame.grid(row=0,column=0,padx=20,pady=20)

        # Client loading bar
        self.client_loading_label = tkinter.Label(self.general_info_frame, text="Loading clients in progress...")
        self.client_loading_label.grid(row=0, column=0)
        self.client_loading = ttk.Progressbar(self.general_info_frame, orient="horizontal", length=100, mode="indeterminate", takefocus=True, maximum=100, value=0)
        self.client_loading.grid(row=1,column=0,padx=20,pady=20)

        for widget in self.general_info_frame.winfo_children():
            widget.grid_configure(padx=10, pady=5)

        if not self.client_loaded:
            # Start the loading bar until everything is loaded
            self.window.after(400, lambda: self.start_progress_bar(True))

        # Start the loop
        self.window.mainloop()

if __name__ == "__main__":
    main = Main()

报错信息

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Utilisateur\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1962, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "c:\Users\Utilisateur\Documents\Batitech\API\test.py", line 97, in <lambda>
    self.client_loading = tkinter.Button(self.general_info_frame, text="Reload clients", command= lambda: self.start_progress_bar(True))
                                                                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\Utilisateur\Documents\Batitech\API\test.py", line 59, in start_progress_bar
    self.thread_client_list.start()
  File "C:\Users\Utilisateur\AppData\Local\Programs\Python\Python312\Lib\threading.py", line 992, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't create new thread at interpreter shutdown

原因分析

问题出在主线程生命周期上:__main__中创建Main实例后,主线程会立即执行完毕并进入退出流程,此时Python解释器启动shutdown机制。尽管GUI线程还在运行(mainloop未结束),但解释器已处于关闭阶段,无法再创建新线程,点击Reload按钮时就会触发错误。

朋友设备能正常运行可能是Python版本或环境的细微差异,但代码本身存在主线程提前退出的问题。

修复方法

1. 让主线程等待GUI线程结束

修改__init__方法,将GUI线程保存为实例变量,然后在__main__中调用join()等待它完成,避免主线程提前退出:

def __init__(self) -> None:
    # ... 其他代码保持不变 ...
    # 保存GUI线程为实例变量
    self.tkinter_start = threading.Thread(target=self.show_gui)
    self.tkinter_start.start()
if __name__ == "__main__":
    main = Main()
    # 等待GUI线程结束后主线程再退出
    main.tkinter_start.join()

2. 给后台线程设置守护属性

在start_progress_bar中创建新线程时,设置daemon=True,避免后台线程阻止程序正常退出:

# Restart loading clients and sites
self.thread_client_list = threading.Thread(target=self.client_list, daemon=True) 
self.thread_client_list.start()
self.thread_get_sites = threading.Thread(target=self.get_sites, daemon=True)
self.thread_get_sites.start()

修改后,主线程会一直等待GUI线程结束,解释器不会提前进入shutdown状态,点击Reload按钮时就能正常创建新线程。

内容的提问来源于stack exchange,提问作者TooFu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:27:39