为什么 __del__ 方法没有被调用?
Why isn't the __del__ method called?
在python3的multiprocess
中,无法调用__del__
方法。
我看过其他关于循环引用的问题,但我找不到multiprocess
中的情况。
foo
中存在循环引用,直接调用foo
时会调用__del__
,而multiprocess
中永远不会调用__del__
被调用。
import multiprocessing
import weakref
class Foo():
def __init__(self):
self.b = []
def __del__(self):
print ('del')
def foo():
print ('call foo')
f = Foo()
a = [f]
# a = [weakref.ref(f)]
f.b.append(a)
# call foo in other process
p = multiprocessing.Process(target=foo)
p.start()
p.join()
# call foo
foo()
输出:
调用 foo
调用 foo
删除
为什么 p
中没有调用 __del__
?
Forked Process
objects 在 运行 使用 os._exit()
完成他们的任务后终止,这会强制终止 child 进程 而无需 正常清理 Python 在退出时执行。循环垃圾没有被清理(因为进程在没有给循环 GC 机会 运行 的情况下终止),它只是掉在地上,留下 OS 清理。
这是故意的,因为正常退出(调用所有正常的清理程序)会冒一些风险,比如未刷新的缓冲区在 parent 和 child 中被刷新(双倍输出),以及其他奇怪的情况分叉进程继承了 parent 的所有状态,但不应使用它,除非明确告知要这样做。
问题实际上不是为什么 没有 在 multiprocess
中调用,而是为什么 在 中调用另一个例子。答案是当您调用 foo
时它不会被调用。它在程序结束时调用。由于程序已完成,Python知道即使它仍然被引用,也可以清除其他任何内容,因此它会清除循环引用。
如果你在脚本末尾添加一个 print
语句,或者从 REPL 调用它,你可以看到 __del__
仍然没有在你的第二个 foo
调用其中一个,但只能在脚本末尾调用。
鉴于 Python 在脚本结束时清除循环引用, 解释了为什么在多处理函数完成时没有发生这种情况。
在python3的multiprocess
中,无法调用__del__
方法。
我看过其他关于循环引用的问题,但我找不到multiprocess
中的情况。
foo
中存在循环引用,直接调用foo
时会调用__del__
,而multiprocess
中永远不会调用__del__
被调用。
import multiprocessing
import weakref
class Foo():
def __init__(self):
self.b = []
def __del__(self):
print ('del')
def foo():
print ('call foo')
f = Foo()
a = [f]
# a = [weakref.ref(f)]
f.b.append(a)
# call foo in other process
p = multiprocessing.Process(target=foo)
p.start()
p.join()
# call foo
foo()
输出:
调用 foo
调用 foo
删除
为什么 p
中没有调用 __del__
?
Forked Process
objects 在 运行 使用 os._exit()
完成他们的任务后终止,这会强制终止 child 进程 而无需 正常清理 Python 在退出时执行。循环垃圾没有被清理(因为进程在没有给循环 GC 机会 运行 的情况下终止),它只是掉在地上,留下 OS 清理。
这是故意的,因为正常退出(调用所有正常的清理程序)会冒一些风险,比如未刷新的缓冲区在 parent 和 child 中被刷新(双倍输出),以及其他奇怪的情况分叉进程继承了 parent 的所有状态,但不应使用它,除非明确告知要这样做。
问题实际上不是为什么 没有 在 multiprocess
中调用,而是为什么 在 中调用另一个例子。答案是当您调用 foo
时它不会被调用。它在程序结束时调用。由于程序已完成,Python知道即使它仍然被引用,也可以清除其他任何内容,因此它会清除循环引用。
如果你在脚本末尾添加一个 print
语句,或者从 REPL 调用它,你可以看到 __del__
仍然没有在你的第二个 foo
调用其中一个,但只能在脚本末尾调用。
鉴于 Python 在脚本结束时清除循环引用,