2

首先,我用flush方法写了一个记录类:

class Recorder
    def __init__(self, buffer_size, path):
        self._big_buffer = np.array(*buffer_size)
        self._path = path
    def push(self, data):
        # insert in self._big_buffer
        # if self._big_buffer is full:
        #     self._flush()
    def flush(self):
        # write buffer to disk (self._path)

然后,我想在退出时刷新:当手动停止、崩溃或任何原因时。

所以我用:

def __init__(self):
    (...)
    atexit.register(self.flush)

而且效果很好。

但是现在,我想用不同的缓冲区大小和不同的路径多次录制、停止录制、再次录制。所以我必须丢弃,然后实例化几个Recorder. 它有点工作,但是 oldRecorder的内存(包含一些 fat self._big_buffer̀)没有被释放,因为它被atexit. 即使我明确调用del. 我不能atexit.unregister(self._flush),因为它只是 Python 3。

我不希望重用现有实例,而是丢弃旧实例并创建新实例。

你会如何处理这样的情况?

4

4 回答 4

4

您可以尝试使用对atexit处理程序的弱引用,因此如果在其他地方删除该对象将不会被保留:

import atexit
import weakref

class CallableMethodWeakRef:
    def __init__(self, object, method_name):
        self.object_ref = weakref.ref(object)
        self.method_name = method_name
    def __call__(self):
        object = self.object_ref()
        if object:
            getattr(object, self.method_name)()

class Recorder:
    def __init__(self, *args):
        atexit.register(CallableMethodWeakRef(self, 'flush'))

    def flush(self):
        print 'flushing'

该方法作为字符串传递,以避免绑定方法弱引用的许多问题,如果您发现它令人不安,您可以随时使用这样的BoundMethodWeakref实现:http ://code.activestate.com/recipes/578298-绑定方法弱引用/

于 2015-08-19T15:20:34.713 回答
2

我会说您正在尝试使用错误的工具。语句和上下文管理器with是一个非常好的工具。文件 IO 是大多数 python 用户将被介绍给 with 语句的主要示例。

f = open("somefile.txt", "w")
try:
    f.write("...")
    # more file operations
finally:
    # regardless of what happens, make sure the files is closed 
    f.close()

变成:

with open("somefile.txt", "w") as f:
    f.write("...")
    # more file operations
# close automatically called at the end of the block

__enter__您可以通过为您的类编写和__exit__方法来创建自己的上下文管理器。

class Recorder
    def __init__(self, buffer_size, path):
        self._big_buffer = np.array(*buffer_size)
        self._path = path
    def push(self, data):
        # insert in self._big_buffer
        # if self._big_buffer is full:
        #     self._flush()
    def flush(self):
        # write buffer to disk (self._path)
    def __enter__(self):
        return self
    def __exit__(self, exctype, exception, traceback):
        # If an exception was thrown in the with block you will get the details here. 
        # If you want the say that the exception has been handled and for it not to be 
        # raised outside the with block then return True
        self.flush()
        # self.close() ?

然后,您将使用您的Recorder对象,例如:

with Recorder(...) as recorder:
    # operations with recorder
    ...
# regardless of what happens the recorder will be flushed at this point
于 2015-08-19T18:40:38.110 回答
0

当然,答案允许您随意Recorder更改路径和缓冲特性。您说“我宁愿不重用现有实例,而是丢弃旧实例并创建新实例。” 但是您没有为此提供任何理由,除非您假设“较旧的 Recorder 的内存(包含一些 fat )没有被释放,因为它由"self._big_buffer̀保留atexit,我认为这是不正确的。

虽然atexit保留对记录器对象的引用是正确的,但这仅意味着只要记录器引用它,缓冲存储器就会被保留。添加方法很容易,close()例如

    def close(self):
        self.flush()
        self._big_buffer = None

和宾果游戏!不存在对缓冲存储器的引用,并且它是可收集的。

您的__init__()方法应该简单地使用 注册atexit,然后该open()方法(它执行__init__()当前执行的其余操作)可以多次使用,每次close()调用之后。

总之,我认为您的问题需要一个对象。

于 2015-08-19T18:06:34.970 回答
0

atexit._exithandlers您可以从(未记录的)列表中手动删除手柄。

import atexit

def unregister(func, *targs, **kargs):

    """unregister a function previously registered with atexit.
       use exactly the same aguments used for before register.
    """
    for i in range(0,len(atexit._exithandlers)):
        if (func, targs, kargs) == atexit._exithandlers[i] :
            del atexit._exithandlers[i]
            return True
    return False

希望有帮助。

于 2018-12-28T11:25:19.383 回答