运行时错误:无法在解释器关闭时创建新线程,而它在另一台计算机上工作得很好

问题描述 投票:0回答:2

我有一个在 VSCode 中运行的 python 程序,但在某一时刻我收到了这个 RuntimeError: can't create new thread atterpreter shutdown ,我什至没有关闭任何东西,我不明白。顺便说一句,相同的程序在我朋友的计算机上运行得非常好(我们有完全相同的程序)

代码(抱歉有点长,但我无法缩短,我已经排除了所有不必要的内容):

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

当我启动程序时,错误没有发生。客户端和站点在启动时加载正常,但是当我在启动时加载客户端后将其更改为按钮时,单击 self.client_chargement 按钮尝试重新加载客户端时,会弹出错误。 我再说一遍,这个完全相同的程序在我朋友的计算机上运行得非常好。

如果您花时间阅读所有内容并回答我,请提前感谢您!

python networking runtime-error editor python-multithreading
2个回答
1
投票

事实上,Python 3.12 引入了一项更改,可以防止在主线程退出后创建新线程。目前尚不清楚它是否被视为错误并会被恢复。有关详细信息,请参阅 CPython 问题 #115533

  • 您现在可以简单地降级到 Python 3.11。

  • 更改主线程的逻辑,使其不会过早退出,而是在返回之前等待所有子线程。这通常是通过在任何子线程上调用

    Thread.join()
    方法来完成的。

    或者,将线程生成转换为使用

    with ThreadPoolExecutor() as executor: ...
    (请参阅文档),它会自动在“with”块末尾等待。


0
投票

我将 VSCode 中的 python 版本(从 3.12)更改为 3.11,现在它可以工作了,我不再有错误了,我真的不知道为什么,但问题来自 python 3.12

© www.soinside.com 2019 - 2024. All rights reserved.