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

时间:2016-04-09 04:25:36

标签: python garbage-collection python-multiprocessing

我使用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

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

有没有办法在python中执行这种gc?

非常感谢。

1 个答案:

答案 0 :(得分:0)

为什么要关闭文件?假设这是一个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,那就会变得更加疯狂。

&#34;它进入f函数,A实例a将无法再访问。&#34; 一般来说,这不是真的。首先,子worker函数返回时退出进程的唯一原因是multiprocessing模块从确保退出的函数调用它。在一般情况下,分叉函数可以返回并执行其父代码。因此,从python的角度来看,a仍然可以访问。此外,您的工作人员可以调用自己触及a的函数。 python无法知道这一点。

python清理所有&#34;不可接受的&#34;将会非常昂贵。叉子后的对象。并且非常危险,因为这些对象可以在很多方面改变系统。