【问题标题】:python: weakref.finalize not run if background threads are alivepython:如果后台线程处于活动状态,weakref.finalize 不会运行
【发布时间】:2018-03-03 09:57:23
【问题描述】:

我想在对象消失时使用weakref.finalize 清理一些后台线程,但是当对象在模块范围内时,终结器没有运行(编辑:)

但是请注意,该对象没有对活动线程的引用,我看不出它没有被垃圾收集的理由。

显式调用del 可以解决问题,但这很不方便。

现场演示:https://ideone.com/kTZsbs

import weakref
import threading


def do(l):
    l.acquire()


class A:
    def __init__(self):
        l = threading.Lock()
        l.acquire()
        t = threading.Thread(target=do, args=[l])
        t.start()

        weakref.finalize(self, A._finalize, t, l)

    @staticmethod
    def _finalize(t, l):
        print("finalizing")
        l.release()
        t.join()


a = A()
# del a does trigger _finalize though

【问题讨论】:

标签: python multithreading garbage-collection


【解决方案1】:

正如@quamrana 所指出的,模块级对象仅在模块卸载时才会被垃圾收集,因此实际上是在解释器退出时。

不幸的是,活动线程也存在于 refcount > 0 的加载线程模块中,这会阻止当前模块被卸载,从而阻止对象被垃圾收集......

所以确保对象是 gc 的唯一方法是限定变量的范围或确保线程自己超时。

【讨论】:

    【解决方案2】:

    您只需要一种方法使a 超出范围:

    def main():
        a = A()
        # when main exits, a will be garbage collected
    
    main()
    

    输出:

    finalizing
    

    【讨论】:

    • 是的,我注意到了这一点,但我不想要求在我的对象上使用范围或上下文,而且我仍然看不出是什么阻止了它被垃圾收集。
    • 经过进一步调查,我发现对线程的引用也存在于创建它们的模块中(threading.enumerate()),这就是为什么模块没有被垃圾收集,对象也没有结果。
    猜你喜欢
    • 2012-11-26
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多