【发布时间】:2020-05-09 01:37:45
【问题描述】:
我正在尝试实现一个 GUI 来帮助一些同事进行图像处理,但我遇到了 Tkinter (ttk) 进度条的问题,当我在另一个线程中执行工作时,它一直滞后。
基本上,我想让进度条在不确定模式下运行并来回弹跳,作为一种视觉确认事情仍在进行中(就像 Windows 中的“工作”圈)。
我是这样设置的:
# Frame/root set up (etc.) above here...
pbv = IntVar()
progressBar = ttk.Progressbar(consoleFrame, orient="horizontal", length=100, variable=pbv, mode="indeterminate")
progressBar.grid(column=1, row=1, sticky=N)
progressBar.start()
root.mainloop()
它会按预期反弹,在主线程上运行良好。到目前为止还不错。
然后,我初始化一个单独的线程并运行一个计算量很大的函数。
externalFunctionThread = threading.Thread(target=expensiveFunctionThread, args=[foo])
externalFunctionThread.deamon = True
externalFunctionThread.start()
有一些功能:
def expensiveFunctionThread(foo):
for i in range(a_few_iterations):
superDuperExpensiveFunction(i, foo)
# Note: Were I to comment this out and replace it with a time.sleep(n), the bar would progress normally
# Even a for loop that prints numbers up to some large integer would not cause lag
就上下文而言,superDuperExpensiveFunction 是对 pyradiomics 函数的调用,该函数从某个图像生成许多纹理特征。
最终发生的情况是,bar 将严重滞后,在 superDuperExpensiveFunction 运行时经常锁定(不移动),仅在每次迭代后移动。超级duper-expensive函数线程一旦结束就会恢复正常。
我查看了此板上的其他线程(How to connect a progress bar to a function?、Tkinter: How to use threads to preventing main event loop from "freezing"、ttk progress bar freezing 等),但它们都没有帮助,因为它们担心进度条在开始时冻结,而不是滞后于其更新。最后一个不起作用(包括 progressBar.update()/progressBar.update_idletasks() 什么都不做)。我担心它与 Python 如何处理线程有关(因为最终只有 1 个“真正的”线程可以一次工作,而 Python 必须循环允许哪个线程工作(GIL 或其他什么? ))。
无论如何,有解决方法吗?为什么会发生这种情况?
【问题讨论】:
-
你可以尝试用multiprocessing代替线程。
标签: python-3.x tkinter progress-bar python-multithreading ttk