【问题标题】:Very slow window refresh (update) via tkinter in macOS [python, PySimpleGUI, Tkinter, macOS]在 macOS [python, PySimpleGUI, Tkinter, macOS] 中通过 tkinter 非常慢的窗口刷新(更新)
【发布时间】:2021-08-27 13:43:03
【问题描述】:

我们的应用程序(基于 Python 的、cythonised 和打包以便在未安装 Python 的计算机上使用)具有基于 PySimpleGUI / Tkinter 端口的 GUI。

在 macOS 中,我们有时会遇到极其缓慢的启动。在我的 Mac 上,从应用程序启动到主窗口完全呈现并准备好使用它只需要大约 2-3 秒。但在一些同事的 Mac 上,有时需要 45 秒甚至几分钟。我们在应用程序的早期版本中遇到了这个问题,但在 5 月份通过添加一个启动窗口解决了这个问题,如PySimpleGUI / Tk: very slow startup on Mac 中所述。新版本(= 带有启动窗口)总是在不同地方的所有可用计算机上快速启动(2-3 秒),但随后(虽然我们没有更改应用程序中的任何内容),慢启动问题再次出现- 仅在某些 Mac 上,甚至取决于位置:在我同事的计算机上,应用程序始终以最大启动。工作时 3 秒,但在家时 45 秒以上。

我们的应用有 Mac、Windows 和 Linux 版本。只有 Mac 版本有这个问题(迄今为止从未在 Win、Linux 下观察到,也从未在 Mac 上的 Win/Linux 模拟器中观察到),仅在某些计算机上与某些位置结合使用。在工作中,我们团队使用的所有计算机都很快,但在我们的一些客人的计算机上却很慢;对我的同事来说,在(她)家慢慢来;在(我的)家里,在我的电脑上很快,但在另一台电脑上很慢。这让我完全困惑!

我在代码中添加了很多日志记录,以便能够查看代码的哪些部分需要花费大量时间。只有一次网络交互(许可证验证),而且似乎并不慢:整个功能(建立连接、检索数据、处理数据、关闭连接)即使启动 45 秒以上也不会超过 2 秒.我们可以看到的所有延迟都与主窗口刷新有关:

logging.info('.created background window', session_log=True)
main_window.refresh()
logging.info('.refreshed main window', session_log=True)

只是这个refresh() 在那些缓慢的启动中需要 3-10 秒甚至更多时间。它是 PySimpleGUI 的一个函数,定义如下:

    def refresh(self):
        if self.TKrootDestroyed:
            return self
        try:
            rc = self.TKroot.update()
        except:
            pass
        return self

在主窗口完全渲染后,同样的函数被多次使用,但它们再也不会慢了;它始终处于应用程序的启动阶段。

所以,似乎是 Tkinter 的 update() 花了这么长时间。但为什么只在某些 Mac 上,以及(在同一台 Mac 上)为什么只在某些地方?

您是否曾在您的 GUI 中遇到过这样的行为?你有任何想法如何处理它?

如果有任何提示,我将不胜感激。

【问题讨论】:

  • 你试过用.update_idletasks()替换.update()吗?调用update 不仅仅是更新显示,它还处理所有未决事件。
  • @BryanOakley 感谢您的提示,我会尝试并在我同事的计算机上测试后通知您。
  • @BryanOakley 是的,它有帮助!它在我的电脑和我同事的电脑上都很好用。您能否发表您的评论作为答案,以便我接受? (我注意到我的电脑上有一个副作用:打开主窗口后,需要关闭 2 个临时窗口,.close()(Tkinter 的 .destroy())现在每个需要几秒钟;我已经解决了推迟关闭出口。)

标签: python tkinter macos-big-sur pysimplegui


【解决方案1】:

我建议用.updateidletasks() 替换对.update() 的调用。 update 不仅会导致窗口刷新,而且还必须处理所有类型的所有未决事件,并且在处理完所有事件之前不会返回。如果在处理事件时再次调用此代码,则最终会出现嵌套在事件循环内的事件循环。

updateidletasks 只处理空闲队列中的事件,这主要是屏幕更新和带有after_idle 的作业队列,大大降低了您最终出现嵌套事件循环的机会。

【讨论】:

    猜你喜欢
    • 2020-04-14
    • 1970-01-01
    • 2010-12-29
    • 2017-05-09
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 2020-05-29
    • 2014-01-27
    相关资源
    最近更新 更多