与 joblib 并行的 tkinter 进度条

tkinter progress bar with joblib parallel

我想制作一个GUI进度条来显示Joblib的进度。

下面是我现在所做的:

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()

现在可以使用 tqdm 模块在终端中显示进度。但是我想问一下,我怎样才能让它在tkinter中用进度条显示进度window?

我试图在 fun() 中调用 progress_bar.step(),但程序只是冻结。抱歉,我对 tkinter 不熟悉。

我已经解决了这个问题,但我知道这绝对不是最好的方法。这是我的代码:

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()

对于这个方法,我使用了一个全局变量n来跟踪Joblib的进度。另外,重要的是 Joblib 的任务应该是一个子进程,否则,它会冻结 tk window。我知道使用全局变量不是一个好习惯,但是 fun() 中全局变量的开销似乎并不高。至少用这个方法,进度条是可以用的。