进度条在单独的线程tkinter上滞后于计算密集型函数

问题描述 投票:1回答:1

[我正在尝试实现一个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函数的调用,该函数从某些图像生成许多纹理特征。

最终发生的是,条形将严重滞后,在superDuperExpensiveFunction运行时会频繁锁定(不移动),仅在每次迭代后才移动。一旦超级duper昂贵的功能线程完成,它将恢复正常。

我看过板上的其他线程(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之类的? ))。

无论如何,是否有解决方法?为什么会发生这种情况?

python-3.x tkinter progress-bar python-multithreading ttk
1个回答
0
投票

好的,因此,在进行了一些研究之后,我发现,双拼词法具有禁止这种快速任务切换的标记,因此线程化不是可行的解决方案。为了解决该问题,按照Furas的建议,我实现了多处理(实际上是池化!)。这不仅使我的进度条运行没有任何滞后,而且还实现了跨内核划分计算,从而极大地加快了我的实现。语法与线程的语法非常相似,但有一个主要的例外,在我弄清楚它之前,这让我非常难过。子进程不会继承变量!因此,如果我想从Entry或其他东西中获取值,则必须将其显式传递给子进程。除此之外,确实没有太多变化。除了使用线程外,还可以使用关联的进程(进程而不是Thread,使用multiprocessing.Queue而不是queue)。没有滞后,效率更高!

© www.soinside.com 2019 - 2024. All rights reserved.