Very slow window refresh (update) via tkinter in macOS [python, PySimpleGUI, Tkinter, macOS]

Our app (Python-based, cythonised and packaged for usage on computers without installed Python) has its GUI based on PySimpleGUI / Tkinter port.

In macOS, we sometimes experience an extremely slow start. On my Mac, from app launch until the main window is completely rendered and ready to use it only takes about 2-3 seconds. But on some of my colleagues' Macs, it sometimes takes 45s or even several minutes. We had this problems with an earlier version of the app but solved it in May by adding a splash window as discussed in PySimpleGUI / Tk: very slow startup on Mac. The new version (= with the splash window) always started quickly (2-3s) on all available computers at various places for several weeks but then (while we haven't changed anything in the app), the slow-start problem appeared again - only on some Macs and even depending on the location: on my colleague's computer, the app always starts in max. 3s at work, but 45s+ when she's at home.

There are Mac, Windows and Linux versions of our app. Only the Mac version has this problem (so far never observed under Win, Linux and also never in Win/Linux emulators on Mac), only on some computers in combination with some locations. At work, it's quick for all the computers our team uses but slow on computers of some of our guests; for my colleague, slow at (her) home; at (my) home, quick on my computer but slow on another one. This is what completely puzzles me!

I've added a lot of logging to the code to be able to see which parts of code take a lot of time. There's only one network interaction (license verification) and it doesn't seem to be slow: the whole function (setting up connection, retrieving the data, processing the data, closing the connection) does not take more than 2s even with those 45s+ starts. All the delays we can see are related to main-window refresh:

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

Just this refresh() takes anything between 3-10s or even more on those slow starts. It is a function of PySimpleGUI defined like this:

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

The same functions are used many times after the main window has been rendered completely, but then they are never slow again; it's always just in the start phase of the application.

So, it seems to be Tkinter's update() that takes so long. But why only on some Macs, and (on the same Macs) why only at some places?

Have you ever experienced such a behaviour in your GUI? Do you have any ideas how to deal with it?

I'd be very grateful for any hints.

Upvotes: 2

Views: 1878

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 386342

I recommend replacing calls to .update() with .updateidletasks(). update not only causes the window to refresh, but it has to process all pending events of all types, and won't return until all events are processed. If, while processing an event this code is called again, you end up with event loops nested inside of event loops.

updateidletasks only process the events in the idle queue, which is mostly screen updates and jobs queue with after_idle, greatly reducing the chance you will end up with nested event loops.

Upvotes: 4

Related Questions