当另一个线程处于活动状态时,为什么不在全局对象上调用__del__?

时间:2019-01-28 18:36:34

标签: python python-3.x multithreading deadlock destructor

我正在一个项目,该项目的结构与以下代码所示的结构类似。我希望有一个对象可以在创建时打开线程,并在对象被销毁时自动将其关闭。当在函数中实例化对象时,此方法按预期方式工作,但是在全局范围内创建对象时,未调用__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()函数或类似方法的解决方案,我是只是好奇地听到可以执行自动清除的替代方案的想法),否则反驳并告诉我我做错了什么?

1 个答案:

答案 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__现在是您可靠的清除方法。