【问题标题】:Python - is `threading.Event` "set" during garbage collection?Python - 在垃圾收集期间是否“设置”了“threading.Event”?
【发布时间】:2016-06-17 03:12:01
【问题描述】:

这篇文章的标题几乎概括了我的问题 - 如果该事件已被垃圾收集,是否会通知等待 Event 的线程?在我的特殊情况下,我有一个类,它的实例有一个 Event 作为属性,我想知道是否应该在这个类上实现一个 __del__ 方法,在垃圾收集之前调用 self.event.set()

我是异步的新手,所以如果事件在垃圾收集时不set(),那么这样做可能是不好的做法,最好让线程挂起?提前感谢您的任何回复。

【问题讨论】:

  • 你可以为你的问题编写一个测试吗?

标签: python multithreading events garbage-collection


【解决方案1】:

由于其他对象持有对事件的引用,事件本身不会被删除或垃圾收集。它不知道您的对象正在被删除。您是否希望您的类有一个__del__ 在对象被删除时设置事件(通过使其引用计数自然归零或通过垃圾收集)完全取决于您的事件系统设计。假设我有十几个引用该事件的对象。我是否希望在每个事件消失时触发事件?视情况而定!

【讨论】:

  • 呃!我并没有真正考虑过这样一个事实,即如果一个线程正在等待一个事件,它就必须引用它,从而防止它被垃圾收集。但是,我很确定set() 方法只是将标志设置为True,所以即使有12 个对象尝试set,它也只会通知一次(除非每次都重置)?
  • 您可以获得 12 到 1 个事件触发器,具体取决于等待线程为事件提供服务的速度以及它对事件的处理方式。如果您希望在删除所有持有该事件的对象时终止等待线程......这可能有点困难,因为您必须跟踪此类对象的数量。 (除非你只有 1 个这样的对象......那么计数很容易!)。
  • 在我的例子中,事件不是对象的公共属性,所以它应该只是该特定对象的set。唯一的公开行动是wait。最终我实现了一个类似于this的承诺系统。
【解决方案2】:

请注意,等待Event 不一定意味着Event 不在垃圾箱中。 循环垃圾是一种可能性,这是另一种可能性:

import threading

class C(object):
    def __init__(self):
        self.e = threading.Event()

    def __del__(self):
        print("going away")

def f():
    C().e.wait()

t = threading.Thread(target=f)
t.start()
print("main ending")

打印出来的:

going away
main ending

然后它永远挂起,因为 Python 尝试 .join() 线程作为解释器关闭处理的一部分。

函数f() 在线程中运行,创建C 的实例,在检索到其e 属性后立即变为垃圾。于是它的__del__方法被调用,显示“going away”。

您可以从行为推断,不,垃圾Event 确实不会被魔法设置。但它不会在实践中出现,所以不用担心;-)

【讨论】:

  • 我正在实现一个类似于this 的承诺系统。每个 Promise 都有一个事件,每当一个 Promise 被解决时,它的关联事件就是set()。我主要担心的是,在某些情况下,未解决的承诺可能会从内存中删除。似乎有安全网(或者可能是错误?)是合理的。
  • 请注意,为了回答您打算提出的问题,我撒了一点谎;-) 也就是说,在我的示例中,Event 并不是真正的垃圾,因为C().e.wait()e.wait 部分创建一个绑定方法对象,该对象包含对 Event 的引用,并且可以从线程访问。在您正在做的事情中,您似乎提供了自己的 wait() 方法,并且访问这些方法同样会创建绑定的方法对象,这将使 your 对象在技术上保持活跃(而不是垃圾)。我无法回答您是否想通过魔术set 您的对象,除了指出魔术在异步上下文中很少有帮助。
猜你喜欢
  • 1970-01-01
  • 2011-04-17
  • 2011-02-25
  • 2010-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-21
  • 2018-08-15
相关资源
最近更新 更多