Python 为什么不是';t称为?;

Python 为什么不是';t称为?;,python,python-3.x,python-multiprocessing,circular-reference,finalizer,Python,Python 3.x,Python Multiprocessing,Circular Reference,Finalizer,在python3的多进程中,无法调用\uuu del\uu方法 我读过关于循环引用的其他问题,但在多进程中找不到这种情况 在foo中有一个循环引用,当直接调用foo时,将调用\uu del\uu,但在multiprocess中,将永远不会调用\uu del\uu import multiprocessing import weakref class Foo(): def __init__(self): self.b = [] def __del__(self

在python3的
多进程
中,无法调用
\uuu del\uu
方法

我读过关于循环引用的其他问题,但在
多进程
中找不到这种情况

foo
中有一个循环引用,当直接调用
foo
时,将调用
\uu del\uu
,但在
multiprocess
中,将永远不会调用
\uu del\uu

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
中不调用
\uuuu del\uuuu

分叉
进程
对象在使用运行其任务后终止,这会强制终止子进程,而不需要Python在退出时执行的正常清理。循环垃圾没有被清理(因为进程在没有给循环GC运行机会的情况下被终止),它只是被扔到地板上,留下操作系统来清理


这是有意为之的,因为正常退出(调用所有正常的清理过程)会使未刷新的缓冲区在父级和子级中都被刷新(输出加倍),当一个分叉进程继承了父进程的所有状态,但除非被明确告知要使用它,否则不应该使用它时所涉及的其他奇怪现象。

分叉
进程
对象在使用运行其任务后终止,这会强制终止子进程,而Python不会在退出时执行正常的清理。循环垃圾没有被清理(因为进程在没有给循环GC运行机会的情况下被终止),它只是被扔到地板上,留下操作系统来清理


这是有意为之的,因为正常退出(调用所有正常的清理过程)会使未刷新的缓冲区在父级和子级中都被刷新(输出加倍),当一个分叉进程继承了父进程的所有状态,但除非被明确告知要使用它,否则不应该使用它时,会涉及到其他奇怪的情况。

问题不是为什么在
多进程中不调用它,而是为什么在另一个示例中调用它。答案是,当你调用
foo
时,它不会被调用。它在节目结束时被调用。由于程序已经完成,Python知道其他任何东西都可以被清除,即使它仍然被引用,因此它会清除循环引用

如果在脚本末尾添加
print
语句,或者从REPL调用该语句,则可以看到
\uuuu del\uuu
也不会在第二次
foo
调用时调用,而只会在脚本末尾调用


假设Python在脚本结束时清理循环引用,解释了为什么在多处理函数完成时不会发生循环引用。

问题实际上不是为什么在
multiprocess
中不调用循环引用,而是为什么在另一个示例中调用循环引用。答案是,当你调用
foo
时,它不会被调用。它在节目结束时被调用。由于程序已经完成,Python知道其他任何东西都可以被清除,即使它仍然被引用,因此它会清除循环引用

如果在脚本末尾添加
print
语句,或者从REPL调用该语句,则可以看到
\uuuu del\uuu
也不会在第二次
foo
调用时调用,而只会在脚本末尾调用


假设Python在脚本结束时清理循环引用,解释了为什么在多处理函数完成时不会发生这种情况。

您认为weakref
做了什么?你在代码中提到了它,它与这个问题相关,但你没有说为什么你认为它相关。你认为weakref有什么作用?您在代码中提到了它,它与这个问题有关,但您没有说为什么您认为它是相关的。大部分详细信息都记录在上,但简短的版本是,它按时间段维护受监视引用的池,并更频繁地清理较新的池,而较旧的池则不那么频繁,时间间隔由执行的分配和解除分配的数量决定。也就是说,只要存在一个活动(非循环)引用,循环收集就不重要(因为它还不是循环垃圾)。我很小心地没有说它只发生在那时,但我确实有点暗示了它。我不确定,但我认为这通常只发生在那时,但如果您需要,您可以在
gc
中调用一些东西,或者如果内存不足,它可能会检查。很高兴知道它有时会在结束之前发生。Python会间歇性地清理循环引用,而不仅仅是在脚本终止时。大部分详细信息都记录在上,但简短的版本是,它按时间段维护受监视引用的池,并更频繁地清理较新的池,而较旧的池则不那么频繁,时间间隔由执行的分配和解除分配的数量决定。也就是说,只要存在一个活动(非循环)引用,循环收集就不重要(因为它还不是循环垃圾)。我很小心地没有说它只发生在那时,但我确实有点暗示了它。我不确定,但我认为这通常只发生在那时,但如果您需要,您可以在
gc
中调用一些东西,或者如果内存不足,它可能会检查。不管怎样,知道它有时发生在结束之前是件好事。