1 回答

TA贡献1824条经验 获得超6个赞
对于您的主线程而言,如果不调用join
所有非守护程序线程而结束,或者对不执行该操作会做出任何假设,则是一个不好的主意。
如果你没有做任何事情非常不寻常的,CPython的(至少2.0 - 3.3)将自动调用覆盖你join
所有的非守护线程作为对_MainThread._exitfunc
。实际上并没有文档记录,因此您不应该依赖它,但这就是您正在发生的事情。
您的主线程实际上根本没有退出;它在_MainThread._exitfunc
尝试使用join
任意非守护进程线程时阻塞了内部。它的对象在atexit
调用处理程序之前不会最终确定,直到完成所有非守护程序线程的连接之后才会发生。
同时,如果您避免这种情况(例如,直接使用thread
/_thread
或通过将主线程从其对象中分离或强制其进入普通Thread
实例),会发生什么情况?没有定义。该threading
模块根本没有引用它,但是在CPython 2.0-3.3中,并且可能在任何其他合理的实现中,它都由thread
/_thread
模块来决定。而且,正如文档所说:
当主线程退出时,系统定义其他线程是否存活。在使用本机线程实现的SGI IRIX上,它们可以生存。在大多数其他系统上,它们是在不执行try ... finally子句或执行对象析构函数的情况下被杀死的。
因此,如果设法避免使用join
所有非守护程序线程,则必须编写代码来处理它们,使其像守护程序线程一样被硬杀死,并使它们继续运行直到退出。
如果它们确实继续运行(至少在POSIX系统上的CPython 2.7和3.3中),则可能仍保留主线程的OS级线程句柄以及代表该线程的各种更高级别的Python对象,并且它们不会被GC清除。 。
最重要的是,即使所有内容都已发布,您也不能依靠GC删除任何内容。如果您的代码依赖于确定性GC,在很多情况下,您都可以在CPython中使用它(尽管您的代码随后将在PyPy,Jython,IronPython等中中断),但是在退出时并不是其中之一。CPython可以而且会在退出时泄漏对象,并让OS对其进行整理。(这就是为什么您永远不会关闭的可写文件可能会丢失最后的几次写操作-该__del__
方法永远不会被调用,因此没有人告诉他们flush
,并且至少在POSIX上,底层FILE*
也不会自动刷新。)
如果您希望在主线程完成时清理某些内容,则必须使用某种close
函数而不是依靠__del__
,并且必须确保通过with
围绕主代码块,atexit
函数或其他机制。
最后一件事:
我本来希望将线程局部变量释放(即收集垃圾)...
您实际上在某处有线程局部变量吗?或者,您是说仅在一个线程中访问的局部变量和/或全局变量?
添加回答
举报