python: weakref.finalize not run if background thr

2019-08-26 17:11发布

问题:

I wanted to use weakref.finalize to cleanup some background threads when an object goes out of sight, but the finalizer is not run (edit:) when the object is in the module scope.

Note however that the object own no reference to the active threads, I can see no reason for it not to be garbage collected.

An explicit call to del solves the issue but this is inconvenient.

live demo here: 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

回答1:

As noted by @quamrana, module level objects only get garbage collected when the module is unloaded, so when the interpreter exits in practice.

Unfortunately, active threads also live in the loaded threading module with a refcount > 0, which prevents the current module from being unloaded and therefore the object from being garbage collected...

So the only way to ensure the object is gc is to scope the variable or make sure the threads timeout by themselves.



回答2:

You just need a way to make a go out of scope:

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

main()

Output:

finalizing