Search code examples
pythontkinterpython-multithreading

tkinter GUI lagging due to a function in after() call


I'm currently trying to update the labels' texts on my tkinter GUI where I get the update label texts from a separate function that calls to APIs and retrieves data. However, I have noticed that while the labels' texts are successfully updating through after(), the GUI becomes very sluggish and unresponsive, taking 3-4 seconds for the window to move after I drag it across the screen. Here are parts of my code below that are relevant. I have modified it to run tkinter on a separate thread, but I'm not too sure about it as I'm new to multi-threading. I would appreciate any advice.

class App(threading.Thread,):
    def __init__(self):
        threading.Thread.__init__(self)
        self.start()

    def callback(self):
        self.root.quit()

    def update_top_coin_list(self, update_ticker_label_list, update_kimp_enter_label_list, update_kimp_exit_label_list):
        usdt_krw = get_usdt_krw_yfinance()
        for (coin_button, coin_kimchi_enter, coin_kimchi_exit) in zip(update_ticker_label_list, update_kimp_enter_label_list, update_kimp_exit_label_list):
            coin_kimchi_enter['text'], coin_kimchi_exit['text'] = get_info_single_coin(coin_button['text'], usdt_krw, 'Binance')
        self.root.after(1000, self.update_top_coin_list, update_ticker_label_list, update_kimp_enter_label_list, update_kimp_exit_label_list)

    def run(self):
        self.root = tk.Tk()
        self.root.protocol("WM_DELETE_WINDOW", self.callback)

        self.root.geometry("900x225")
        self.root.resizable(0, 0)

        # Redacted code here for frames/widgets/etc not super relevant to the issue

        # Run first time
        self.update_top_coin_list(coin_button_list, coin_kimchi_enter_list, coin_kimchi_exit_list)

        self.root.mainloop()

Ask you can see, the function get_info_single_coin is called within the update_top_coin_list which is run every 1 second. The lists themselves are very short (5 values) so that's not the issue but the function get_info_single_coin calls to APIs and retrieves data. I'm thinking that's causing the GUI to become sluggish. Is there any solution to this?


Solution

  • The function get_info_single_coin, retrieves data from APIs, network requests can be time-consuming, and inside a GUI that is what may cause the unresponsiveness.

    Lets do those API call into separate threads.

    def update_top_coin_list(self, update_ticker_label_list, update_kimp_enter_label_list, update_kimp_exit_label_list):
        def thread_update(coin_button, coin_kimchi_enter, coin_kimchi_exit):
            usdt_krw = get_usdt_krw_yfinance()
            coin_kimchi_enter['text'], coin_kimchi_exit['text'] = get_info_single_coin(coin_button['text'], usdt_krw, 'Binance')
            self.root.after(1000, self.update_top_coin_list, update_ticker_label_list, update_kimp_enter_label_list, update_kimp_exit_label_list)
    
        for coin_button, coin_kimchi_enter, coin_kimchi_exit in zip(update_ticker_label_list, update_kimp_enter_label_list, update_kimp_exit_label_list):
            threading.Thread(target=thread_update, args=(coin_button, coin_kimchi_enter, coin_kimchi_exit)).start()