1 回答

TA貢獻(xiàn)1824條經(jīng)驗(yàn) 獲得超6個(gè)贊
對(duì)于您的主線程而言,如果不調(diào)用join
所有非守護(hù)程序線程而結(jié)束,或者對(duì)不執(zhí)行該操作會(huì)做出任何假設(shè),則是一個(gè)不好的主意。
如果你沒有做任何事情非常不尋常的,CPython的(至少2.0 - 3.3)將自動(dòng)調(diào)用覆蓋你join
所有的非守護(hù)線程作為對(duì)_MainThread._exitfunc
。實(shí)際上并沒有文檔記錄,因此您不應(yīng)該依賴它,但這就是您正在發(fā)生的事情。
您的主線程實(shí)際上根本沒有退出;它在_MainThread._exitfunc
嘗試使用join
任意非守護(hù)進(jìn)程線程時(shí)阻塞了內(nèi)部。它的對(duì)象在atexit
調(diào)用處理程序之前不會(huì)最終確定,直到完成所有非守護(hù)程序線程的連接之后才會(huì)發(fā)生。
同時(shí),如果您避免這種情況(例如,直接使用thread
/_thread
或通過將主線程從其對(duì)象中分離或強(qiáng)制其進(jìn)入普通Thread
實(shí)例),會(huì)發(fā)生什么情況?沒有定義。該threading
模塊根本沒有引用它,但是在CPython 2.0-3.3中,并且可能在任何其他合理的實(shí)現(xiàn)中,它都由thread
/_thread
模塊來決定。而且,正如文檔所說:
當(dāng)主線程退出時(shí),系統(tǒng)定義其他線程是否存活。在使用本機(jī)線程實(shí)現(xiàn)的SGI IRIX上,它們可以生存。在大多數(shù)其他系統(tǒng)上,它們是在不執(zhí)行try ... finally子句或執(zhí)行對(duì)象析構(gòu)函數(shù)的情況下被殺死的。
因此,如果設(shè)法避免使用join
所有非守護(hù)程序線程,則必須編寫代碼來處理它們,使其像守護(hù)程序線程一樣被硬殺死,并使它們繼續(xù)運(yùn)行直到退出。
如果它們確實(shí)繼續(xù)運(yùn)行(至少在POSIX系統(tǒng)上的CPython 2.7和3.3中),則可能仍保留主線程的OS級(jí)線程句柄以及代表該線程的各種更高級(jí)別的Python對(duì)象,并且它們不會(huì)被GC清除。 。
最重要的是,即使所有內(nèi)容都已發(fā)布,您也不能依靠GC刪除任何內(nèi)容。如果您的代碼依賴于確定性GC,在很多情況下,您都可以在CPython中使用它(盡管您的代碼隨后將在PyPy,Jython,IronPython等中中斷),但是在退出時(shí)并不是其中之一。CPython可以而且會(huì)在退出時(shí)泄漏對(duì)象,并讓OS對(duì)其進(jìn)行整理。(這就是為什么您永遠(yuǎn)不會(huì)關(guān)閉的可寫文件可能會(huì)丟失最后的幾次寫操作-該__del__
方法永遠(yuǎn)不會(huì)被調(diào)用,因此沒有人告訴他們flush
,并且至少在POSIX上,底層FILE*
也不會(huì)自動(dòng)刷新。)
如果您希望在主線程完成時(shí)清理某些內(nèi)容,則必須使用某種close
函數(shù)而不是依靠__del__
,并且必須確保通過with
圍繞主代碼塊,atexit
函數(shù)或其他機(jī)制。
最后一件事:
我本來希望將線程局部變量釋放(即收集垃圾)...
您實(shí)際上在某處有線程局部變量嗎?或者,您是說僅在一個(gè)線程中訪問的局部變量和/或全局變量?
添加回答
舉報(bào)