2019年12月26日 / 950次阅读 / Last Modified 2019年12月28日
tkinter,多线程
在编写GUI程序的时候,对于比较耗时的操作(比如按一个Button开始长时间的计算),常规的思路都是扔给线程去计算,这样可以保持GUI界面不会出现卡死。我也是这么干的!由于希望界面上的Text控件还能输出计算过程的log,我在启动线程后,调用了线程的join函数。
python创建线程并启动后,可以通过调用线程的join函数进入阻塞状态,以此等待线程结束后再往下执行。我的初衷时,tkinter界面卡死没关系,线程在运行并在输出log(界面上的Text控件),这时界面卡死也是需要的,要等线程结束才能让用户按其它按钮。
结果,我遇到了deadlock,死锁!tkinter界面也因此彻底卡死。
分析了一下界面彻底卡死的原因,原来是这样的:
创建并启动线程后,调用线程的join函数,界面卡死等待线程执行结束;此时,tkinter界面的Text控件已经被join函数锁死;线程在计算过程中,需要访问Text控件写log,因此在写log的地方开始死等。死锁!
我的代码是这样的:
def __write():
1498 try:
1499 _name, _oui, _pn, _ver,_wlen, _sp, _sn, _date = __get_cont()
1500 except ValueError as e:
1501 eblog.error(repr(e))
1502 return
1503 rth = threading.Thread(
1504 target=_write_check_vendor,
1505 args=(_name,_oui,_pn,_ver,_wlen,_sp,_sn,_date,eblog),
1506 daemon=True)
1507 rth.start()
1508 #rth.join() Deadlock: GUI is locked here, eblog is not usable.
_write_check_vendor函数要使用界面上的eblog(就是Text),__write函数对应界面上的一个按钮,点击后进入。如果在__write内调用rth.join函数,死锁!
tkinter界面彻底卡死原因找到后,就有了解决方案:
GUI程序虽然使用方便,不过开发效率和执行效率确实相对较低。稍不注意,还容易在写log时界面卡死,进入死锁!要小心啊。。。
-- EOF --
本文链接:https://www.pynote.net/archives/1633
《tkinter界面因线程join卡死的案例》有6条留言
©Copyright 麦新杰 Since 2019 Python笔记
移动窗口时,右键不松开,此时tkinter的GUI也是卡死状态!额... [ ]
本文卡死是因为在独立的线程中更新GUI的widget,在Google,Stackoverflow上基本都是不推荐子线程里更新GUI。不知道tkinter的Text控件,是不是线程安全的? [ ]
写了个测试程序,多线程不停地写Text空间,未见输出混乱。 [ ]
在__write中直接操作eblog,他们在同一个线程中,不会卡死,只是Text的显示有些滞后,表现为所有的显示在最后一刻突然出现。但在另一个线程中操作eblog,由于__write函数中有join阻塞,再加上对eblog的调用不会返回,就出现了死锁。问题是:为什么在另一个线程操作eblog,它就不返回了呢? [ ]
python解释器能判断,对tkinter界面上各个控件的操作,是在同一线程中,还是别的线程。在同一线程中,不阻塞,这是合理的设计。点击功能按钮,界面要有所反应,如果界面其它部分也不返回,一点就卡死了!而对于别的线程的访问,阻塞,按照代码流程执行。 [ ]
GUI是一个单线程,点击Button后不返回,其它对界面元素的操作,都会卡死,包括定时器after中的操作。 [ ]