gos*_*som 2 python memory multiprocessing
我有一个应该永远运行的程序.这是我在做的事情:
from myfuncs import do, process
class Worker(multiprocessing.Process):
def __init__(self, lock):
multiprocesing.Process.__init__(self)
self.lock = lock
self.queue = Redis(..) # this is a redis based queue
self.res_queue = Redis(...)
def run():
while True:
job = self.queue.get(block=True)
job.results = process(job)
with self.lock:
post_process(self.res_queue, job)
def main():
lock = multiprocessing.Semaphore(1)
ps = [Worker(lock) for _ in xrange(4)]
[p.start() for p in ps]
[p.join() for p in ps]
Run Code Online (Sandbox Code Playgroud)
self.queue和self.res_queue是两个与python stdlib Queue类似的对象,但它们使用Redis数据库作为后端.
函数进程对作业所承载的数据(主要是html解析)进行一些处理并返回字典.
函数post_process通过检查某些条件将作业写入另一个redis队列(一次只有一个进程可以检查锁定原因的条件).它返回True/False.
该程序每天使用的内存正在增加.有人可以弄清楚发生了什么吗?
当运行方法中的作业超出范围时,内存应该是免费的吗?
当运行方法中的作业超出范围时,内存应该是免费的吗?
首先,范围是整个run方法,它永远循环,所以永远不会发生.(此外,退出run方法时,进程关闭,无论如何都释放了内存......)
但即使它确实超出范围,这也不意味着你认为它意味着什么.Python不像C++,其中存在存储在堆栈中的变量.所有对象都存在于堆上,并且它们保持活动状态,直到不再有对它们的引用为止.超出范围的变量意味着变量不再引用它曾经引用的任何对象.如果该变量是对象的唯一引用,则它将被释放*,但如果您在其他地方有其他引用,则在其他引用消失之前,不能释放该对象.
与此同时,超出范围并没有什么神奇之处.变量停止引用对象的任何方式都具有相同的效果 - 无论是变量超出范围,是否调用del它,或者为其分配新值.因此,每次循环,当你这样做时job =,你就会删除之前的引用,job即使没有任何东西超出范围.(但请记住,您将有两个工作在高峰时段,而不是一个,因为新的工作在旧的工作被释放之前被拉出队列.如果这是一个问题,您可以job = None在阻塞队列之前一直做.)
因此,假设问题实际上是job对象(或它拥有的东西),问题是你没有向我们展示的一些代码是在某处保留对它的引用.
在不知道你在做什么的情况下,很难建议修复.它可能只是"不存储那里".或者它可能是"存储weakref而不是对象本身".或者"添加LRU算法".或者"添加一些流量控制,这样如果你得到太多备份,你就不会继续工作,直到你的内存耗尽".
*在CPython中,这会立即发生,因为垃圾收集器基于引用计数.另一方面,在Jython和IronPython中,垃圾收集器只依赖于底层VM的垃圾收集器,因此在JVM或CLR注意到它不再被引用之前,该对象不会被释放,这通常不是立即的,并且是不确定的.