Tkinter 中的多线程通信,不会产生不必要的线程

Mulithreaded communication in Tkinter without spawning unnecessary threads

提问人:TheGodParticle 提问时间:11/16/2023 最后编辑:TheGodParticle 更新时间:11/16/2023 访问量:36

问:

我有一个 Tkinter 应用程序,其中每毫秒调用一个函数以更新 GUI。update()x

update()看起来像这样:

def update(self):
   # update some gui variables
   if self.point_iteration_done and not overall_point_done (and some other bools are true):
      self.do_point()

   self.after(x ms, self.update)

do_point()将变量设置为 ,然后启动名为 的函数的线程。point_iteration_doneFalsepoint_thread_handler()

def do_point(self):
   self.point_iteration_done = False
   point_thread = Thread(target=point_thread_handler, args=..., daemon=True).start()

point_thread_handler(self)调用从另一个类导入的实际指向函数(可能需要几秒钟才能执行),然后一旦完成,就会发布一个虚拟事件:self.event_generate(<<PointingThreadFinished>>")

def point_thread_handler(self):
   # check some conditions, then
   self.PointClass.point(args=...)
   self.event_generate("<<PointingThreadFinished>>")

然后,在 GUI 类的构造函数中有一行,将 设置为,然后读取 的值(在另一个线程的指向类中设置)。self.bind("<<PointingThreadFinished>>", lambda event: self.on_pointing_complete())on_pointing_complete()point_iteration_doneTrueoverall_pointing_done

def on_pointing_complete(self):
   self.point_iteration_done = True
   if self.pointing.overall_pointing_done:
            self.is_overall_pointing_done = True

我遇到的问题是,在某些情况下,当最多只有 2 个线程(一个用于 Tkinter 主循环,一个用于指向)时,会生成超过 10 个额外的线程(有时多达 10 个或更多)。我知道这一点,因为在关闭 GUI 时,我有时会看到:

Exception in thread Thread-10 (pointing_thread_handler):
File "C:\Users\...", line 400, in pointing_thread_handler
    self.event_generate("<<PointingThreadFinished>>")
  File "C:\Program Files\Python311\Lib\tkinter\__init__.py", line 1914, in event_generate
    self.tk.call(args)
RuntimeError: main thread is not in main loop

有没有更好的方法来优雅地处理线程之间的创建和通信,以确保永远不会形成额外的、不必要的线程?

更准确地说,对于这种情况,只有在完成前一个点螺纹时,才应形成点螺纹。

Python 多线程 tkinter

评论

0赞 TheLizzard 11/16/2023
你能提供一个最小的可重现的例子吗(你可以用 )替换长执行函数?您如何以及何时产生新线程?另外,您如何确认您有 10 个线程同时运行?time.sleep(3)
0赞 TheGodParticle 11/16/2023
@TheLizzard刚刚更新了上面的问题,提供了更多细节。我知道由于发生异常,有超过 2 个线程(见上文)
0赞 acw1668 11/16/2023
point_iteration_done是内部的局部变量,而不是全局变量。do_point()
0赞 OM222O 11/16/2023
这是编写 GUI 的特别糟糕的方式,与其创建每个 Xms 执行更新的动画帧,不如尝试使用异步库。它会让你的生活更轻松,用户体验更好。
0赞 TheLizzard 11/17/2023
您收到的错误只是抱怨,因为您从另一个线程调用。不建议从创建 .这将使您的程序变得非常复杂,但您可以设置一个布尔变量。您可以有一个循环来检查是否设置了布尔变量而不是 .tkinter.event_generatetkintertk.Tk()event_generate.after.bind

答: 暂无答案