for*_*tyj 19 python garbage-collection generator coroutine
当不再使用发电机时,应该进行垃圾收集,对吧?我尝试了以下代码,但我不确定哪个部分我错了.
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()
Run Code Online (Sandbox Code Playgroud)
在最后一行,我打电话给垃圾收集器,因为没有再打电话cd了.gc应该是自由的cd.但是当我打电话时cdw.next(),它仍然打印8.我再试了几次cdw.next(),它可以成功打印所有其余的,直到StopIteration.
我试过这个是因为我想了解生成器和协同程序是如何工作的.在David Beazley的PyCon演讲"关于协同程序和并发的好奇课程"的幻灯片28中,他说一个协程可以无限期地运行,我们应该用.close()它来关闭它.然后他说垃圾收集器会打电话.close().根据我的理解,一旦我们打电话给.close()自己,gc就会.close()再次打电话.会gc收到警告说它无法调用.close()已经关闭的协程吗?
谢谢你的任何投入.
mgi*_*son 10
由于python的动态特性,在cd你到达当前例程的末尾之前不会释放引用,因为(至少)python的Cpython实现没有"预读".(如果你不知道你正在使用什么python实现,那几乎肯定是"Cpython").如果一个对象在一般情况下仍然存在于当前命名空间中(例如,您仍然可以通过调用到达它locals()),那么解释器几乎不可能确定对象是否应该是空闲的.
在一些不太常见的情况下,其他python实现可能能够在当前堆栈帧结束之前释放对象,但Cpython不会打扰.
试试这段代码,证明生成器可以在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()
Run Code Online (Sandbox Code Playgroud)
当引用计数达到0时,对象(包括生成器)被垃圾收集(在Cpython中 - 其他实现可能以不同的方式工作).在Cpython中,引用计数仅在您看到del语句时或者由于当前命名空间更改而导致对象超出范围时递减.
重要的是,一旦没有对象的引用,垃圾收集器就可以自由清理它.实现如何确定没有更多引用的详细信息留给您正在使用的特定python发行版的实现者.
在您的示例中,生成器在脚本结束之前不会收集垃圾.Python不知道你是否会cd再次使用它,所以它不能扔掉它.准确地说,在全局命名空间中仍然存在对生成器的引用.
当引用计数降至零时,生成器将获得GCed ,就像任何其他对象一样.即使发电机没有耗尽.
这可能发生在许多正常情况下 - 如果它的本地名称超出范围,如果它是deled,如果它的所有者获得GCed.但是,如果任何活动对象(包括名称空间)拥有对它的强引用,它将不会获得GCed.
| 归档时间: |
|
| 查看次数: |
2120 次 |
| 最近记录: |