python 使用多进程启动进程后进行垃圾回收

python garbage collection after start process using multiprocess

我测试了 python 在使用多进程启动进程后执行的 gc 行为:

from multiprocessing import Process
import time

class A(object):
    def __del__(self):
        print 'deleting'

def f(name):
    import gc
    gc.collect()
    print 'hello', name
    print [map(lambda s: str(s)[:64], gc.get_referrers(o)) for o in gc.get_objects() if isinstance(o, A)]
    time.sleep(123)

def main():
    a=A()
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()


if __name__ == '__main__':
    try:
        main()
    except:
        print 'sdfsdf!'

输出:

hello bob
[["[[], {'__setattr__': <slot wrapper '__setattr__' of 'object' obj", '<frame object at 0xb87570>', '<frame object at 0xbd7f80>']]

我想通过执行 __del__ 来关闭文件描述符。 当子进程启动时,它进入 f 函数并且 A 实例 a 将不再可用。但是 __del__ 没有被执行,这意味着 a 对象仍然没有被释放。输出显示它似乎被框架对象持有。

所以我尝试了另一种使用Exception清理堆栈的方法来尝试释放无法访问的对象并执行__del__函数:

from multiprocessing import Process
import time
import sys

class GcHelp(Exception):
    def __init__(self, func):
        self.func = func
        super(GcHelp, self).__init__(func.__name__)

class A(object):
    def __del__(self):
        print 'deleting'

def f():
    print 'target function'


def raiser():
    raise GcHelp(f)

def main():
    a=A()
    p = Process(target=raiser, args=())
    p.start()
    p.join()


if __name__ == '__main__':
    try:
        main()
    except GcHelp as e:
        sys.exc_clear()
        e.func()
    except:
        print 'sdfsdf!' 

输出:

Process Process-1:
Traceback (most recent call last):
  File "/usr/lib64/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib64/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "gc1.py", line 19, in raiser
    raise GcHelp(f)
GcHelp: f

似乎多进程已经准备好清理堆栈并接管所有异常handling.But父框架不再存在。但是为什么框架仍然存在于第一个代码示例中?显然它仍然持有 a 并且对象根本没有被释放。

有什么方法可以在 python 中执行这种 gc 吗?

非常感谢。

为什么要关闭文件?假设这是一个 linuxy 系统,一个分叉的环境,好吧,分叉很奇怪。如果您关闭子文件中的文件,它将刷新仍在缓冲区中的所有数据...但是相同的数据将在父文件中再次刷新,从而导致重复数据。

import multiprocessing as mp

fd = None

def worker():
    # child closes file, flushing "1"
    fd.close()

def doit():
    global fd
    fd = open('deleteme', 'w')
    fd.write('1')
    p = mp.Process(target=worker)
    p.start()
    p.join()
    # parent closes file, flushing "1"
    fd.close()
    # lets see what we got
    print(open('deleteme').read())

doit()

此脚本打印 11,因为子文件对象和父文件对象都写了 1。如果任何一方调用 flushseek.

,它会变得更加疯狂

"it enters the f function and the A instance a would no longer be reachable." 一般情况下是不正确的。首先,子工作函数在 returns 时退出进程的唯一原因是 multiprocessing 模块从确保退出的函数调用它。在一般情况下,分叉函数可以 return 并执行其父代码。因此,从 python 的角度来看,a 仍然可以访问。此外,您的工作人员可以调用一个本身涉及 a 的函数。 python 无法知道这一点。

python 在 fork 之后清理所有 "unreferencable" 对象的成本非常高。而且非常危险,因为这些对象可以通过多种方式改变系统。