Memory leaks IPython.parallel模块内存泄漏?

Memory leaks IPython.parallel模块内存泄漏?,memory-leaks,parallel-processing,ipython,Memory Leaks,Parallel Processing,Ipython,我正在使用IPython.parallel来处理集群上的大量数据。我运行的远程功能如下所示: def evalPoint(point, theta): # do some complex calculation return (cost, grad) 此函数将调用以下函数: def eval(theta, client, lview, data): async_results = [] for point in data: # evaluate

我正在使用IPython.parallel来处理集群上的大量数据。我运行的远程功能如下所示:

def evalPoint(point, theta):
    # do some complex calculation
    return (cost, grad)
此函数将调用以下函数:

def eval(theta, client, lview, data):
    async_results = []
    for point in data:
        # evaluate current data point
        ar = lview.apply_async(evalPoint, point, theta)
        async_results.append(ar)

    # wait for all results to come back
    client.wait(async_results)

    # and retrieve their values
    values = [ar.get() for ar in async_results]

    # unzip data from original tuple
    totalCost, totalGrad = zip(*values)

    avgGrad =  np.mean(totalGrad, axis=0)
    avgCost = np.mean(totalCost, axis=0)

    return (avgCost, avgGrad)
如果我运行代码:

client = Client(profile="ssh")
client[:].execute("import numpy as np")        

lview = client.load_balanced_view()

for i in xrange(100):
    eval(theta, client, lview, data)
内存使用量一直在增长,直到最终耗尽(76GB内存)。我简化了
evalPoint
以确保它不是罪魁祸首

eval
的第一部分是从IPython关于如何使用负载平衡器的文档中复制的。第二部分(解压和平均)相当简单,所以我认为这不是内存泄漏的原因。此外,我还尝试在
eval
中手动删除对象,并调用
gc.collect()
,但没有成功

我希望有IPython.parallel经验的人能指出一些明显的错误,或者能够确认这实际上是内存泄漏

另外一些事实:

  • 我正在Ubuntu 11.10上使用Python 2.7.2
  • 我使用的是IPython版本0.12
  • 我的引擎运行在服务器1-3上,客户端和集线器运行在服务器1上。如果我把所有的东西都放在服务器1上,我会得到类似的结果
  • 我发现的唯一一件类似于IPython内存泄漏的事情与
    %run
    有关,我相信这在这个版本的IPython中已经修复(另外,我没有使用
    %run
更新

此外,我尝试将日志记录从内存切换到SQLiteDB,以防出现问题,但仍然存在相同的问题

响应(1)

内存消耗肯定在控制器中(我可以通过:(a)在另一台机器上运行客户端,以及(b)观察top来验证这一点)。我没有意识到非SQLiteDB仍然会消耗内存,所以我没有费心清理

如果我使用DictDB和purge,我仍然会看到内存消耗增加,但速度要慢得多。它在2GB左右徘徊了20次eval()调用

如果我使用MongoDB和purge,看起来mongod占用了大约4.5GB的内存,而ipcluster占用了大约2.5GB的内存

如果使用SQLite并尝试清除,则会出现以下错误:

File "/usr/local/lib/python2.7/dist-packages/IPython/parallel/controller/hub.py", line 1076, in purge_results
  self.db.drop_matching_records(dict(completed={'$ne':None}))
File "/usr/local/lib/python2.7/dist-packages/IPython/parallel/controller/sqlitedb.py", line 359, in drop_matching_records
  expr,args = self._render_expression(check)
File "/usr/local/lib/python2.7/dist-packages/IPython/parallel/controller/sqlitedb.py", line 296, in _render_expression
  expr = "%s %s"%null_operators[op]
TypeError: not enough arguments for format string

所以,我想如果我使用DictDB,我可能会没事(今晚我要试着跑步)。我不确定是否仍会有一些内存消耗(我也会按照您的建议在客户端中进行清除)。

是控制器进程在增长,还是客户端在增长,还是两者都在增长

控制器会记住所有请求和所有结果,因此将此信息存储在简单dict中的默认行为将导致持续增长。使用db后端(sqlite或最好是mongodb,如果有的话)可以解决这个问题,或者可以使用
客户端。purge_results()
方法来指示控制器放弃任何/所有结果历史记录(如果您使用的是db历史记录,这将从db中删除它们)

客户机本身在其
results
dict中缓存自己的所有结果,因此这也会随着时间的推移导致增长。不幸的是,这一个更难处理,因为引用可以向所有方向传播,并且不受控制器的db后端的影响

这是IPython中的一个示例,但现在,您应该能够通过删除客户端结果/元数据目录中的条目来手动清除引用,如果您的视图仍然存在,则它有自己的结果目录:

# ...
# and retrieve their values
values = [ar.get() for ar in async_results]

# clear references to the local cache of results:
for ar in async_results:
    for msg_id in ar.msg_ids:
        del lview.results[msg_id]
        del client.results[msg_id]
        del client.metadata[msg_id]
或者,您可以使用simple
dict.clear()
清除整个客户端缓存:

旁注:


视图有自己的wait()方法,因此您根本不需要将客户机传递给函数。所有内容都应该可以通过视图访问,如果您确实需要客户端(例如清除缓存),您可以通过
视图获取。客户端

感谢您花时间回复!我没有足够的空间来正确地回答所有问题,所以我把其余的回答放在问题的底部。我昨天晚上能够跑完全程,所以只要我使用DictDB,我的问题就解决了。我猜MongoDB可能会有一个限制内存使用的选项,但这是另一个问题。我想补充一点:一个有趣的事情是DictDB对我的进程的运行速度比MongoDB或SQLite快得多。我猜这是由于进程完成的速度和簿记的开销造成的。谢谢,我修复了sqlite的打字错误。db后端的一部分要点是不需要清除结果。如果您仍然使用它,我建议您尽可能少地使用它。新设计的一部分优点是,速度慢的集线器无法降低执行速度,但只有在不总是阻塞集线器操作的情况下,这才是正确的。另外,请参见和。至少对于SQLiteDB,如果不清除,它会占用我所有的内存。感谢您提供MongoDB的信息。那么,从理论上讲,这是否意味着我应该能够运行Mongo而无需清除?
view.results.clear()
client.results.clear()
client.metadata.clear()