Search code examples
pythonpython-3.xtkinterprogress-bar

tkinter progress bar with joblib parallel


I would like to make a GUI progress bar to show the progress of Joblib.

Here below is what I have done now:

import tkinter as tk
from tkinter import ttk
from tqdm import tqdm
from joblib import Parallel, delayed

def fun(_):
    return _ ** 2
def main():
    result = Parallel(n_jobs=-1, backend='threading')(delayed(fun)(_) for _ in tqdm(range(1024 ** 2)))
    print(result)

root = tk.Tk()
progress_bar = ttk.Progressbar(root, mode='determinate')
progress_bar.pack()
button = tk.Button(root, text='start', command=main)
button.pack()
root.mainloop()

Now it is able to show the progress in the terminal with the tqdm module. But I would like to ask, how can I make it to show the progress with the progress bar in tkinter window?

I have tried to call progress_bar.step() in fun(), but the program just freeze. Sorry that I am unfamiliar with tkinter.


Solution

  • I have kind of solved the question, but I know this is definitely not the best method. Here is my code:

    import tkinter as tk
    from tkinter import ttk
    from tqdm import tqdm
    from joblib import Parallel, delayed
    from threading import Thread
    
    n = 0
    
    def fun(_):
        global n
        n += 1
        return _ ** 2
    
    def main():
        def parallel():
            nonlocal result
            result = Parallel(n_jobs=-1, backend='threading')(delayed(fun)(_) for _ in range(1024 ** 2))
        
        result = None
        progress_bar['maximum'] = 1024 ** 2  # number of items that loops in Parallel
        process = Thread(target=parallel, daemon=True)
        process.start()
        """
        update progress bar
        """
        while progress_bar['value'] < 1024 ** 2:
            progress_bar['value'] = n
            root.update_idletasks()
            root.update()  # prevent freezing
        process.join()
    
        print(result)
    
    root = tk.Tk()
    progress_bar = ttk.Progressbar(root, mode='determinate')
    progress_bar.pack()
    button = tk.Button(root, text='start', command=main)
    button.pack()
    root.mainloop()
    

    For this method, I have used a global variable n to track the progress of Joblib. Also, it is important that the Joblib's task should be a subprocess, otherwise, it will freeze the tk window. I know that using a global variable is not a good habit, but seems the overhead of a global variable in fun() is not high. At least with this method, the progress bar is functionable.