我正在一个项目,该项目的结构与以下代码所示的结构类似。我希望有一个对象可以在创建时打开线程,并在对象被销毁时自动将其关闭。当在函数中实例化对象时,此方法按预期方式工作,但是在全局范围内创建对象时,未调用__del__
,从而导致程序挂起。
import threading
def thread(event):
event.wait()
print("Terminating thread")
class ThreadManager:
def __init__(self):
self.event = threading.Event()
self.thread = threading.Thread(target=thread, args=(self.event,))
self.thread.start()
def __del__(self):
self.event.set()
print("Event set")
self.thread.join()
if __name__ == '__main__':
print("Creating thread")
manager = ThreadManager()
#del manager
除非我明确删除manager
对象,否则程序将挂起。我猜想解释器将等待删除全局对象,直到所有非守护进程线程都完成为止,从而导致死锁。
我的问题是,有人可以确认这一点并提供解决方法吗(我已经读过this页,所以我不是在寻找使用close()
函数或类似方法的解决方案,我是只是好奇地听到可以执行自动清除的替代方案的想法),否则反驳并告诉我我做错了什么?
答案 0 :(得分:0)
与C ++之类的语言不同,Python不会在对象超出范围时立即销毁它们,这就是__del__
不可靠的原因。您可以在这里阅读有关此内容的更多信息:https://stackoverflow.com/a/35489349/5971137
关于解决方案,我认为这是上下文管理器(with
)的完美案例:
>>> import threading
>>>
>>> def thread(event):
... event.wait()
... print("Terminating thread")
...
>>> class ThreadManager:
... def __init__(self):
... print("__init__ executed")
... self.event = threading.Event()
... self.thread = threading.Thread(target=thread, args=(self.event,))
... self.thread.start()
... def __enter__(self):
... print("__enter__ executed")
... return self
... def __exit__(self, *args):
... print("__exit__ executed")
... self.event.set()
... print("Event set")
... self.thread.join()
...
>>> with ThreadManager() as thread_manager:
... print(f"Within context manager, using {thread_manager}")
...
__init__ executed
__enter__ executed
Within context manager, using <__main__.ThreadManager object at 0x1049666d8>
__exit__ executed
Event set
Terminating thread
print
语句显示执行顺序按照您希望的方式工作,其中__exit__
现在是您可靠的清除方法。