如果不再使用Python生成器但尚未达到StopIteration,是否会对其进行垃圾回收? [英] Will a Python generator be garbage collected if it will not be used any more but hasn't reached StopIteration yet?

查看:68
本文介绍了如果不再使用Python生成器但尚未达到StopIteration,是否会对其进行垃圾回收?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当不再使用生成器时,应该对其进行垃圾收集,对吗?我尝试了以下代码,但不确定是哪一部分错了。

When a generator is not used any more, it should be garbage collected, right? I tried the following code but I am not sure which part I was wrong.

import weakref
import gc

def countdown(n):
    while n:
        yield n
        n-=1

cd = countdown(10)
cdw = weakref.ref(cd)()
print cd.next()
gc.collect()
print cd.next()
gc.collect()
print cdw.next()

在第二行中,我调用了垃圾收集器,由于不再有呼叫 cd 的电话。 gc 应该释放 cd 的权利。但是当我调用 cdw.next()时,它仍在打印8。我尝试了更多的 cdw.next(),它可以成功打印其余所有内容,直到StopIteration。

On the second last line, I called garbage collector and since there is no call to cd any more. gc should free cd right. But when I call cdw.next(), it is still printing 8. I tried a few more cdw.next(), it could successfully print all the rest until StopIteration.

我尝试这样做是因为我想了解生成器和协程的工作方式。在大卫·比兹利(David Beazley)在PyCon演示文稿协程和并发性的好奇课程的幻灯片28上,他说协程可能会无限期运行,我们应该使用 .close()关闭它下。然后他说垃圾收集器将调用 .close()。据我了解,一旦我们自己调用 .close() gc 就会调用 .close () gc 会收到警告,称无法在已经关闭的协程中调用 .close()吗?

I tried this because I wanted to understand how generator and coroutine work. On slide 28 of David Beazley's PyCon presentation "A Curious Course on Coroutines and Concurrency", he said that a coroutine might run indefinitely and we should use .close() to shut it down. Then he said that garbage collector will call .close(). In my understanding, once we called .close() ourselves, gc will call .close() again. Will gc receive a warning that it can't call .close() on an already closed coroutine?

感谢任何输入。

推荐答案

由于python的动态特性,在您到达当前例程末尾之前,不会释放对 cd 的引用,因为(至少)python的Cpython实现不会提前读取。 (如果您不知道使用的是哪种python实现,则几乎可以肯定是 Cpython)。有许多微妙之处使解释器几乎无法确定对象是否应该是自由的(如果在一般情况下该对象仍存在于当前名称空间中)(例如,您仍然可以通过调用<$ c $来访问它) c> locals())。

Due to the dynamic nature of python, the reference to cd isn't freed until you reach the end of the current routine because (at least) the Cpython implementation of python doesn't "read ahead". (If you don't know what python implementation you're using, it's almost certainly "Cpython"). There are a number of subtleties that would make that virtually impossible for the interpreter to determine whether an object should be free if it still exists in the current namespace in the general case (e.g. you can still reach it by a call to locals()).

在一些不太常见的情况下,其他python实现可能能够在当前堆栈帧结束之前释放对象,但Cpython不会打扰。

In some less general cases, other python implementations may be able to free an object before the end of the current stack frame, but Cpython doesn't bother.

请尝试使用以下代码,该代码表明可以免费在Cpython中清理生成器:

Try this code instead which demonstrates that the generator is free to be cleaned up in Cpython:

import weakref
def countdown(n):
    while n:
        yield n
        n-=1

def func():
    a = countdown(10)
    b = weakref.ref(a)
    print next(a)
    print next(a)
    return b

c = func()
print c()

对象(包括生成器)是垃圾当其引用计数达到0时收集(在Cpython中-其他实现可能会有所不同)。在Cpython中,仅当您看到 del 语句或由于当前名称空间更改而导致对象超出范围时,引用计数才会减少。

Objects (including generators) are garbage collected when their reference count reaches 0 (in Cpython -- Other implementations may work differently). In Cpython, reference counts are only decremented when you see a del statement, or when an object goes out of scope because the current namespace changes.

重要的是,一旦不再有对对象的引用,则可以自由地由垃圾收集器对其进行清理。该实现如何确定没有更多参考的详细信息留给您正在使用的特定python发行版的实现。

The important thing is that once there are no more references to an object, it is free to be cleaned up by the garbage collector. The details of how the implementation determines that there are no more references are left to the implementers of the particular python distribution you're using.

这篇关于如果不再使用Python生成器但尚未达到StopIteration,是否会对其进行垃圾回收?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆