在多线程 Python 进程中,我有许多非守护线程,我的意思是即使在主线程退出/停止后也能保持主进程活动的线程。
我的非守护线程在主线程中持有对某些对象的弱引用,但是当主线程结束时(控制从文件底部脱落)这些对象似乎没有被垃圾收集,我的弱引用终结器回调没有不开火。
我期望主线程被垃圾收集是错误的吗?我本来期望线程本地将被释放(即垃圾收集)......
我错过了什么?
配套材料
显示主线程的输出pprint.pprint( threading.enumerate() )
已停止,而其他人继续前进。
[<_MainThread(MainThread, stopped 139664516818688)>,
<LDQServer(testLogIOWorkerThread, started 139664479889152)>,
<_Timer(Thread-18, started 139663928870656)>,
<LDQServer(debugLogIOWorkerThread, started 139664437925632)>,
<_Timer(Thread-17, started 139664463103744)>,
<_Timer(Thread-19, started 139663937263360)>,
<LDQServer(testLogIOWorkerThread, started 139664471496448)>,
<LDQServer(debugLogIOWorkerThread, started 139664446318336)>]
而且由于有人总是询问用例...
我的网络服务偶尔会错过它的实时截止日期(这在最坏的情况下会导致整个系统故障)。事实证明,这是因为只要文件系统发脾气,记录(重要)调试数据就会阻塞。因此,我试图改造一些已建立的专用日志库,以将阻塞 I/O 推迟到工作线程。
遗憾的是,已建立的使用模式是记录重叠并行事务的短期日志通道和从未显式关闭的长期模块范围通道的混合。
所以我创建了一个装饰器,它将方法调用推迟到工作线程。工作线程是非守护进程,以确保所有(慢)阻塞 I/O 在解释器退出之前完成,并持有对客户端的弱引用(方法调用入队)。当客户端被垃圾回收时,弱引用的回调触发并且工作线程知道没有更多的工作将被排队,因此将在下次方便时退出。
除了一个重要的用例之外,这似乎在所有情况下都可以正常工作:当日志通道位于主线程中时。当主线程停止/退出时,日志通道尚未最终确定,因此我的(非守护程序)工作线程继续保持整个进程处于活动状态。