废弃的发电机所拥有的资源将如何处理?

时间:2019-02-16 21:26:24

标签: python python-3.x

我有一个生成器功能,可以从文件中读取行并将其解析为对象。这些文件太大了,无法考虑将整个文件处理为一个列表,这就是为什么我使用生成器而不是列表的原因。

我很担心,因为在调用生成器时,我的代码有时会中断。如果找到了要查找的内容,则可以选择停止,然后再从文件中读取每个对象。我真的不了解废弃的生成器会发生什么,或更重要的是,我不知道打开的文件句柄会发生什么。

我想避免这里的资源泄漏。


示例代码:

def read_massive_file(file_path)
    with open(file=file_path, mode='r', encoding='utf-8') as source_file:
        for line in source_file:
            yield parse_entry(line)

for entry in read_massive_file(my_file):
    if is_the_entry_i_need(entry):
        break
else:
    # not found
    pass

我的问题是:上面的代码会打开我的源文件,还是python找到关闭它的方法?

我从for循环中消费的事实是否有任何改变?如果我在放弃迭代器之前为read_massive_file()手动获得了一个迭代器并调用了next()几次,我会看到相同的结果吗?

2 个答案:

答案 0 :(得分:4)

这只会在CPython上迅速释放资源。要真正注意这种情况下的资源释放,您必须执行类似的操作

with contextlib.closing(read_massive_file(my_file)) as gen:
    for entry in gen:
        ...

但我从未见过有人这样做。


当生成器被丢弃而没有完全耗尽时,生成器的__del__方法将向生成器中抛出GeneratorExit异常,以触发__exit__方法和finally块。在CPython上,这会在循环中断后立即发生,并且仅丢弃对生成器的引用,但是在其他实现上,例如PyPy,它可能仅在GC循环运行时发生,或者在GC不运行时根本不发生在程序结束之前。

GeneratorExit将根据您的情况触发文件关闭。可能会意外捕获GeneratorExit并继续执行,在这种情况下,可能不会触发适当的清除操作,但您的代码不会执行此操作。

答案 1 :(得分:0)

您永远不会保存read_massive_file的返回值;唯一的引用由for循环生成的代码在内部保存。一旦该循环完成,就应该对生成器进行垃圾收集。

如果你写的话会有所不同

foo = read_massive_file(my_file):
for entry in foo:
    ...
else:
    ...

现在,您必须等到foo超出范围(或明确称为del foo)之后才能收集生成器。