【问题标题】:Garbage collection of object after exception异常后对象的垃圾收集
【发布时间】:2011-01-18 18:04:56
【问题描述】:

我观察到,在发生异常后,我有一个未调用构造函数的对象,这会导致持有锁。改善这种情况的最佳方法是什么?在 except 块中调用 del 会是解决方案吗?

b=BigHash(DB_DIR, url)
meta = bdecode(b.get())
return meta

b 持有一个在销毁时释放的锁(它是一个 C++ 对象) b.get() 抛出异常。

【问题讨论】:

    标签: python exception-handling destructor


    【解决方案1】:

    无论如何,您都希望释放锁——无论是否引发异常。在这种情况下,最好在 finally: 子句中释放锁定/删除 b:

    b=BigHash(DB_DIR, url)
    try:
        meta = bdecode(b.get())
    finally:
        del b # or whatever you need to do to release the lock
    return meta
    

    您还可以使用上下文管理器 - http://docs.python.org/library/stdtypes.html#typecontextmanager。只需在BigHash.__exit__函数中添加释放锁的代码,该函数将在离开with块后调用,代码如下:

    with BigHash(DB_DIR, url) as b:
        meta = bdecode(b.get())
    return meta
    

    【讨论】:

    • 令人惊讶的是,在 python 2.5.4 中,这不适用于“with”。没有调用析构函数。
    • @piotr:您的 BigHash 类必须定义 __exit__ 方法才能很好地与 with 配合使用。见docs.python.org/reference/…
    【解决方案2】:

    你需要做这样的事情来确保 b 处于解锁状态

    b=BigHash(DB_DIR, url)
    try:
        meta = bdecode(b.get())
        return meta
    finally:
        #unlock b here
    

    如果 BigHash 可以作为上下文工作,那么您可以编写一个更简洁的方法

    with b as BigHash(DB_DIR, url):
        meta = bdecode(b.get())
        return meta
    

    您可能需要向 BigHash 添加一些代码以使其作为上下文工作

    【讨论】:

    • 我不能使用“with”或其他语言技巧吗?从 C++ 中,我发现超出范围的对象没有被破坏是有问题的。
    • @plotr,对象超出范围时被破坏,但可能修改了BigHash的锁定状态。你能显示 BigHash 的来源吗?
    • 这是几百行 C++,所以这是不切实际的。重要的一点是桶在构造函数上被锁定而在析构函数上被解锁。而 python 的 GC 似乎将对象留在周围。
    • 在这种情况下你不会使用except,你会使用finally。您不会在 any 实例中使用裸 except(没有裸 raise)。
    • @piotr,现有代码的大小无关紧要,您只需要添加__enter____exit__ 方法即可使其与with 一起使用。另一种方法是用锁管理器包装类。
    【解决方案3】:

    在一个名字上调用del 是你几乎不应该做的事情。 调用del 并不能保证对底层对象将发生什么有用的事情。您永远不应该依赖__del__ 方法来处理您需要发生的事情。

    del 只删除一个对对象的引用,当您可能不假思索地做出更多时,这可能会令人困惑。因此,del 对清理命名空间很有用,而不是用于控制对象的生命周期,它甚至不是很好——控制名称生命周期的正确方法是将其放入函数并让它超出范围或将其放入 with 块中。

    您需要使用releaseunlockclose 方法为BigHash 配备显式 释放锁的能力。如果您想将它与上下文管理器 (with) 一起使用,您可以定义 __exit__,它将在可预测的有用时间被调用。

    【讨论】:

      猜你喜欢
      • 2010-11-08
      • 2012-04-21
      • 1970-01-01
      • 2020-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多