8

我正在使用多处理处理大量数据,存储在字典中。基本上我所做的只是加载一些签名,存储在字典中,从中构建一个共享的 dict 对象(获取 Manager.dict() 返回的“代理”对象)并将这个代理作为参数传递给具有在多进程中执行。

只是为了澄清:

signatures = dict()
load_signatures(signatures)
[...]
manager = Manager()
signaturesProxy = manager.dict(signatures)
[...]
result = pool.map ( myfunction , [ signaturesProxy ]*NUM_CORES )

现在,如果签名少于 200 万个左右,一切都会完美运行。无论如何,我必须处理一个带有 5.8M 键的字典(二进制格式的酸洗签名会生成一个 4.8 GB 的文件)。在这种情况下,进程会在创建代理对象期间终止:

Traceback (most recent call last):
  File "matrix.py", line 617, in <module>
signaturesProxy = manager.dict(signatures)
  File "/usr/lib/python2.6/multiprocessing/managers.py", line 634, in temp
token, exp = self._create(typeid, *args, **kwds)
  File "/usr/lib/python2.6/multiprocessing/managers.py", line 534, in _create
id, exposed = dispatch(conn, None, 'create', (typeid,)+args, kwds)
  File "/usr/lib/python2.6/multiprocessing/managers.py", line 79, in dispatch
raise convert_to_error(kind, result)
multiprocessing.managers.RemoteError: 
---------------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.6/multiprocessing/managers.py", line 173, in handle_request
    request = c.recv()
EOFError
---------------------------------------------------------------------------

我知道数据结构很大,但我正在使用配备 32GB RAM 的机器,运行 top 我看到加载签名后的进程占用 7GB 的 RAM。然后它开始构建代理对象,RAM 使用量上升到 ~17GB RAM,但从未接近 32。此时,RAM 使用量开始迅速减少,进程因上述错误而终止。所以我想这不是由于内存不足错误......

有什么想法或建议吗?

谢谢,

戴维德

4

4 回答 4

6

你为什么不试试这个数据库?数据库不限于可寻址/物理内存,并且对于多线程/进程使用是安全的。

于 2010-12-26T17:27:01.360 回答
2

为了节省时间并且不必调试系统级问题,也许您可​​以将 580 万条记录字典分成三组,每组约 200 万,然后运行 ​​3 次作业。

于 2010-12-26T17:24:26.847 回答
0

我认为您遇到的问题是字典或哈希表随着它的增长而自行调整大小。最初,dict 有一定数量的可用桶。我不确定 Python,但我知道 Perl 以 8 开头,然后当存储桶已满时,哈希会再重新创建 8 个(即 8、16、32,...)。

桶是哈希算法的着陆位置。8 个插槽并不意味着 8 个条目,它意味着 8 个内存位置。添加新项目时,会为该密钥生成一个哈希,然后将其存储到该存储桶中。

这就是碰撞发挥作用的地方。存储桶中的项目越多,函数的速度就越慢,因为由于插槽的动态大小,项目是按顺序附加的。

可能发生的一个问题是您的密钥非常相似并且产生相同的哈希结果 - 这意味着大多数密钥都在一个插槽中。预先分配哈希桶将有助于消除这种情况并实际上改善处理时间和密钥管理,而且它不再需要进行所有交换。

但是,我认为您仍然受限于可用的连续内存量,最终需要使用数据库解决方案。

旁注:我还是 Python 的新手,我知道在 Perl 中,您可以通过 print %HASHNAME 查看哈希统计信息,它会显示您的存储桶使用情况分布。帮助您识别冲突计数 - 以防您需要预先分配存储桶。这也可以在 Python 中完成吗?

富有的

于 2012-02-21T17:43:01.460 回答
-3

如果字典是只读的,则在大多数操作系统中不需要代理对象。

只需在启动工作程序之前加载字典,并将它们放在可以访问的地方;最简单的地方是全局到一个模块。工人可以阅读它们。

from multiprocessing import Pool

buf = ""

def f(x):
    buf.find("x")
    return 0

if __name__ == '__main__':
    buf = "a" * 1024 * 1024 * 1024
    pool = Pool(processes=1)
    result = pool.apply_async(f, [10])
    print result.get(timeout=5)

这仅使用 1GB 的内存组合,而不是每个进程使用 1GB,因为任何现代操作系统都会对分叉之前创建的数据进行写时复制的影子。请记住,其他工作人员不会看到对数据的更改,并且内存当然会分配给您更改的任何数据。

它将使用一些内存:包含引用计数的每个对象的页面将被修改,因此将被分配。这是否重要取决于数据。

这将适用于任何实现普通分叉的操作系统。它不适用于 Windows;它的(残废的)流程模型需要为每个工人重新启动整个流程,因此它不太擅长共享数据。

于 2010-12-26T18:31:19.513 回答