python退出mainloop_不要阻塞tkinter的mainloop
最近被GUI多線程代碼的死鎖問(wèn)題搞的有點(diǎn)頭大,本文總結(jié)一下自己的所思所得,并不代表完全正確,因?yàn)楫吘箾](méi)有去閱讀tk的源代碼。
mainloop,故名思議,它就應(yīng)該是python程序的mainThread。這個(gè)GUI的mainloop,靠事件響應(yīng)驅(qū)動(dòng)。比如有一個(gè)button(A),點(diǎn)A,就是給這個(gè)mainloop傳遞了一個(gè)事件,這個(gè)事件最后會(huì)傳遞到A綁定的commnad函數(shù)中去執(zhí)行。
不要阻塞tkinter的mainloop,就是不要在事件響應(yīng)的函數(shù)中阻塞住,否則GUI會(huì)卡死。常見(jiàn)的現(xiàn)象是,A綁定的函數(shù)執(zhí)行需要那么一點(diǎn)點(diǎn)時(shí)間,點(diǎn)擊下去后,GUI就會(huì)卡住那么一點(diǎn)點(diǎn)時(shí)間。所以,大多數(shù)編程教材都建議使用多線程來(lái)規(guī)避GUI的卡死,即點(diǎn)擊A后啟動(dòng)一個(gè)線程,A綁定的函數(shù)立即返回,釋放GUI(表示GUI有可能接收別的事件的響應(yīng)了),具體工作由線程完成。
由線程來(lái)完成工作,并規(guī)避GUI的卡死,是個(gè)很好的最佳實(shí)踐,不過(guò),我遇到的問(wèn)題是,線程被GUI卡死了!
計(jì)算模型大概是這樣的:多個(gè)線程通過(guò)操作一個(gè)Text控件就是往里寫log;寫log的執(zhí)行流程代碼中,有mutex,用來(lái)多線程間控制Text的狀態(tài);GUI的事件響應(yīng)中,也有mutex.acquire;只要GUI出發(fā)這個(gè)事件,整個(gè)程序就死鎖了。
為什么會(huì)這樣呢?我想來(lái)想去,覺(jué)得出問(wèn)題的地方,就是線程被GUI卡死了。為什么線程會(huì)被卡死呢?因?yàn)榫€程在mutex.acquire中在向GUI發(fā)事件(操作Text),而此時(shí)GUI在等待mutex,于是死鎖。
GUI在一個(gè)事件沒(méi)有處理完的情況下,是無(wú)法處理別的事件的。比如我們?cè)贏的綁定函數(shù)中sleep,整個(gè)GUI上其它地方都點(diǎn)不了(OS會(huì)記錄這些事件,在GUI被釋放后再把這些事件灌給它)。線程中對(duì)Text的操作無(wú)法返回,很可能就是因?yàn)镚UI已經(jīng)被卡死了。
奇怪的是,如果A綁定代碼中也操作Text,不會(huì)卡死,而只是在GUI被釋放后,一口氣把所有的log全顯示出來(lái),log顯示的過(guò)程只是感覺(jué)不流暢而已。區(qū)別在于mainloop中觸發(fā)事件和非mainloop中觸發(fā)(我個(gè)人的理解哈),也許存在內(nèi)部事件和外部事件這樣的區(qū)別,外部事件會(huì)被阻塞,即線程操作Text的代碼被阻塞,而mainloop中操作Text的代碼,只是更新延后。
總之,在GUI中如果有mutex.acquire這樣的代碼,是非常危險(xiǎn)的,一不留神就死鎖。不要阻塞mainloop的事件響應(yīng),用線程是OK的,用戶友好。多線程之間有mutex沒(méi)問(wèn)題,只要GUI的mainloop沒(méi)有被卡死。
-- EOF --
總結(jié)
以上是生活随笔為你收集整理的python退出mainloop_不要阻塞tkinter的mainloop的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux 守护进程_网络工程师之lin
- 下一篇: java 字符串转查找_Java 实例