【问题标题】:Python: flush a buffer before program termination via a finalizerPython:通过终结器在程序终止之前刷新缓冲区
【发布时间】:2010-09-28 03:19:53
【问题描述】:

我保留一个事务缓存,以便在水印或对象终结时刷新(到持久存储)。由于__del__ 在每个对象上都是no longer guaranteed to be called,因此将类似函数(或__del__ 本身)挂钩到atexit.register(在初始化期间)是否合适?

如果我没记错的话,这个导致方法绑定到的对象一直挂起,直到程序终止。这可能不是问题,但也许有更优雅的解决方案?

注意:我知道使用__del__ 是不理想的,因为it can cause uncatchable exceptions,但我想不出另一种方法来做到这一点,除非在我的程序中一直级联finalize() 调用。蒂亚!

【问题讨论】:

    标签: python buffer destructor finalizer


    【解决方案1】:

    如果您必须处理资源,首选方法是显式调用close()finalize() 方法。看看with 声明来抽象它。在您的情况下,weakref 模块可能是一个选项。缓存的对象可以由系统进行垃圾回收,并调用它们的__del__() 方法,或者如果它们还活着,你可以完成它们。

    【讨论】:

    • 你在布赖恩之前给出了解决方案,但他解释得更详细一点,这让它在我脑海中响起。很抱歉——我仍然赞成你的!
    【解决方案2】:

    我认为atexit 是去这里的方式。

    【讨论】:

      【解决方案3】:

      将以下内容放入名为destructor.py的文件中

      import atexit
      
      objects = []
      
      def _destructor():
          global objects
          for obj in objects:
              obj.destroy()
          del objects
      
      atexit.register(_destructor)
      

      现在这样使用它:

      import destructor
      
      class MyObj(object):
          def __init__(self):
              destructor.objects.append(self)
              # ... other init stuff
          def destroy(self):
              # clean up resources here
      

      【讨论】:

      • 模块很酷,但我会投票支持可调用类而不是具有全局变量的模块。
      • @S.Lott:可调用对象不是单例。一个模块对象是。这样我就可以使用单个析构模块来拥有多个模块。
      【解决方案4】:

      我会说atexit 或尝试看看您是否可以将代码重构为能够使用with_statement 表达,该__future__ 在2.5 和2.6 中默认情况下。 2.5 包含一个模块 contextlib 来简化一些事情。我在使用 Canonical 的 Storm ORM 时做过类似的事情。

      未来导入with_statement

      @contextlib.contextmanager
      def start_transaction(db):
        db.start()
        yield
        db.end()
      
      with start_transaction(db) as transaction:
        ...
      

      对于非数据库的情况,您可以只注册要使用全局刷新的对象,然后使用类似的东西。这种方法的好处是它使事情变得明确。

      【讨论】:

        【解决方案5】:

        如果您在执行刷新时不需要您的对象处于活动状态,您可以使用weak references

        这类似于您提出的解决方案,但不是使用真正的引用,而是存储弱引用列表,并带有一个回调函数来执行刷新。这样一来,引用就不会使这些对象保持活动状态,并且您不会在使用 __del__ 方法时遇到任何循环垃圾问题。

        如果需要保证在某个时间点完成,您可以遍历终止时的弱引用列表以手动刷新任何仍然活动的引用。

        【讨论】:

        • 我认为这是我一直在寻找的优雅解决方案——如果一个对象被 GC'd,我从 del 回调管理类。如果不是 GC,弱引用在终止时必须仍然存在于管理类中,我可以挂钩 atexit 回调以使管理类刷新。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-02-27
        • 2012-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-12
        相关资源
        最近更新 更多