【发布时间】:2016-07-14 20:47:15
【问题描述】:
def content_generator(applications, dict):
for app in applications:
yield(app, dict[app])
with open('abc.pickle', 'r') as f:
very_large_dict = pickle.load(f)
all_applications = set(very_large_dict.keys())
pool = multiprocessing.Pool()
for result in pool.imap_unordered(func_process_application, content_generator(all_applications, very_large_dict)):
do some aggregation on result
我有一个非常大的字典,其键是字符串(应用程序名称),值是有关应用程序的信息。由于应用程序是独立的,我想使用多处理来并行处理它们。当字典不是那么大时并行化起作用,但是当字典太大时所有 python 进程都被杀死。我使用dmesg 检查出了什么问题,发现它们因机器内存不足而被杀死。我在池进程运行时做了top,发现它们都占用了相同数量的驻留内存(RES),都是3.4G。这让我感到困惑,因为它似乎已将整个字典复制到生成的进程中。我以为我分解了字典,只通过产生dict[app] 而不是dict 来传递与生成过程相关的内容。对我做错了什么有什么想法吗?
【问题讨论】:
-
您应该考虑的几件事:传递大量数据以进行最少的处理并不是使用多处理的好方法。如果你有小数据,那需要很长的任务,这是一个更好的方法。听起来您的示例不是一个好的用例,除非您在磁盘上序列化了数据,否则可以仅传递路径并在此过程中将其解开。接下来,对于大文件,许多处理成为一个问题。使用信号量来避免内存溢出,以限制活动进程的数量。
-
下一步:你需要考虑管道限制:一个管道只保证在一定大小下具有原子性,一旦你超过了这个限制,你基本上可以保证数据损坏(就像大字典一样):@ 987654321@
-
在 Linux 系统上,新进程由
fork()创建,因此在创建它们时获取整个父进程地址空间的副本。它是“写入时复制”,因此更像是“虚拟”副本而不是“真实”副本,但仍然... ;-) 首先,尝试创建您的Poolbefore 创建庞大的数据结构。然后子进程将继承一个小得多的地址空间。 -
另外,最后,是的:多处理不能使用共享内存,除非你可以传递指向底层 C 数据类型的指针(没有 GIL,比如 numpy 数组,然后不要修改缓冲区的内容) .这意味着复制操作对于字典的多处理是不可避免的。
-
@AlexanderHuszagh,他没有超过他们。他正在传递
content_generator(all_applications, very_large_dict),这是一个生成器,一次产生一对(key, value)。生成器在主进程中运行。
标签: python multiprocessing python-multiprocessing