【问题标题】:__del__ not implicitly called on object when its last reference gets deleted__del__ 在最后一个引用被删除时不隐式调用对象
【发布时间】:2022-12-18 06:38:16
【问题描述】:

我有一个类在它的中启动一个线程__在里面__成员,我想在不再需要该类的实例时加入该线程,所以我在__del__.

结果是__del__当实例的最后一个引用被删除时,永远不会调用成员,但是如果我隐式调用德尔,它被调用。

下面是我的实现的一个较短的修改版本,它显示了这个问题。

import sys
from queue import Queue
from threading import Thread

class Manager:

    def __init__(self):
        ''' 
        Constructor. 
        '''
        # Queue storing the incoming messages.
        self._message_q = Queue()
        # Thread de-queuing the messages.
        self._message_thread = \
            Thread(target=process_messages, args=(self._message_q,))
        # Start the processing messages thread to consume the message queue.
        self._message_thread.start()

    def __del__(self):
        ''' 
        Destructor. Terminates and joins the instance's thread.
        '''
        print("clean-up.")
        # Terminate the consumer thread.
        # - Signal the thread to stop.
        self._message_q.put(None)
        # - Join the thread.
        self._message_thread.join()

def process_messages( message_q):
    ''' 
    Consumes the message queue and passes each message to each registered
    observer.
    '''
    while True:
        print("got in the infinite loop")
        msg = message_q.get()
        print("got a msg")
        if msg is None:
            # Terminate the thread.
            print("exit the loop.")
            break
        # Do something with message here.

mgr = Manager()
print("mgr ref count:" + str(sys.getrefcount(mgr) - 1)) # -1 cause the ref passed to getrefcount is copied. 
#del mgr

控制台为此代码输出以下内容:

mgr ref count:1
got in th infinite loop

由于线程仍在运行,执行挂起。出于某种原因我不明白__del__未被调用,因此线程未终止。

如果我取消注释最后一行 del mgr 以显式删除实例,那么__del__被调用并进行线程清理。

mgr ref count:1
clean-up.
got in the infinite loop
got a msg
exit the loop.
Press any key to continue . . .

有人对此有解释吗?

【问题讨论】:

  • del mgr 删除最后一个引用(mgr 是一个引用),而不是对象。顺便说一句,在删除引用后,垃圾收集器删除对象之前可能会有延迟。
  • __del__ 用于资源管理是错误的。而是定义一个上下文管理器。
  • @PavelShishpor mgr 是对该对象的唯一引用。
  • 如果您想保证在脚本终止之前执行某些操作,请使用 atexit 模块。

标签: python multithreading del


【解决方案1】:

来自the official documentation on __del__

不保证为解释器退出时仍然存在的对象调用__del__()方法。

您在模块级别有一个名为 mgr 的对象引用。该引用在您的程序终止时存在,因此可能会或可能不会调用__del__


要详细说明关于这个问题的一些 cmets,__del__ 应该不是被认为是资源释放器。也就是说,如果您来自 C++,__del__不是相当于析构函数。 __del__ 可能会运行也可能不会运行(例如,如上所述,它不会在程序退出时运行),即使它运行了,它在程序中的运行时间也可能比您预期的要晚得多,具体取决于垃圾收集器的感受你。

如果您正在寻找在以下情况下释放的资源分配这么说吧,你想要一个context manager

我不知道你的确切用例,但如果你想创建一个在特定结束时释放的 mgr 对象堵塞的代码,你可以写这样的东西

class Manager:

    def __enter__(self):
        # Resource allocation goes here
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # Resource deallocation goes here; you
        # can use the arguments to determine
        # if an exception was thrown in the 'with'
        # block
        pass

with Manager(...) as mgr:
    # __enter__ is called here
    ... some code ...
    # __exit__ is called at the end of this
    # block, EVEN IF an exception is thrown.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多