如果一个对象的成员之一是正在运行的线程,它可以被垃圾回收吗?

问题描述 投票:0回答:1

我有一个自定义线程子类,它重复调用“绑定”对象上的方法。目标是每当“绑定”对象被 GC 时自动加入该线程:

from threading import Thread, Event
from weakref import ref, WeakSet
from typing import Callable, Generic
from typing_extensions import TypeVar
import atexit

T = TypeVar("T", bound=object)

_workers: WeakSet = WeakSet()

@atexit.register
def stopAllWorkers():
    # copy because _workers will be mutated during enumeration.
    refs = list(_workers)
    for worker in refs:
        try:
            worker.stop()
        except:
            pass


class MaintenanceWorker(Thread, Generic[T]):

    def __init__(self, bound_to: T, interval: float, task: Callable[[T], None]):
        self._interval = interval
        self._task = task
        self._ref = ref(bound_to, lambda _: self.stop())
        self._finished = Event()
        super().__init__()

    def stop(self):
        self._finished.set()
        _workers.discard(self)

    def run(self):
        self._finished.clear()
        _workers.add(self)
        while True:
            self._finished.wait(self._interval)
            if self._finished.is_set() or (subject := self._ref()) is None:
                _workers.discard(self)
                break
            try:
                self._task(subject)
            except Exception:
                pass
            finally:
                del subject

以下类的实例是否能够被垃圾收集,因为它们的成员之一是正在运行的线程?


class Foo: 

   def __init__(self):
     self._worker = MaintenaceWorker(bound_to=self, interval=15*60.0, Foo.bar)
     self._worker.start()

   def bar(self):
     # some convoluted logic 
     ... 
python multithreading garbage-collection weak-references
1个回答
0
投票

简单的答案是

self._worker = MaintenaceWorker(bound_to=self, interval=15*60.0, Foo.bar)
                                                     stores self ^^^^^^^
class MaintenanceWorker(Thread, Generic[T]):

    def __init__(self, bound_to: T, interval: float, task: Callable[[T], None]):
        self._interval = interval
        self._task = task
        ^^^^^^^^^^^^^^^^^ stores self

如果您调用

task
而不是存储它,那么“函数”应该一直存在,直到它返回并且调用者失去对它的引用,因此该对象不会被垃圾收集。

© www.soinside.com 2019 - 2024. All rights reserved.