【问题标题】:python multiprocessing.pool.map, passing arguments to spawned processespython multiprocessing.pool.map,将参数传递给生成的进程
【发布时间】: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


【解决方案1】:

cmets 变得无法跟上,所以我在这里粘贴我的重要评论:

在 Linux 系统上,新进程由 fork() 创建,因此在创建它们时获取整个父进程地址空间的副本。它是“写时复制”,因此更像是“虚拟”副本而不是“真实”副本,但仍然...... ;-) 首先,在创建巨型数据结构之前尝试创建您的Pool。那么子进程将继承一个小得多的地址空间。

然后是一些问题的答案:

所以在 python 2.7 中,没有办法产生一个新进程?

在 Linux-y 系统上,没有。在 Python 3.4 中首次添加了对它们使用“spawn”的能力。在 Windows 系统上,“spawn”一直是唯一的选择(Windows 上没有 fork())。

大字典作为参数传递给函数,我 只能在此函数内创建池。我怎么能 在大字典之前创建池

就这么简单:将这两行设为程序的前两行:

import multiprocessing
pool = multiprocessing.Pool()

您可以随时创建池(只要它在您实际使用它之前某个时间存在),并且工作进程将继承整个地址空间当时 调用了Pool 构造函数。

另一个建议

如果您在创建 dict 后没有对其进行修改,请尝试改用它:

def content_generator(dict):
    for app in dict:
        yield app, dict[app]

这样您也不必实现一组巨大的键。或者,甚至更好(如果可能),跳过所有这些并直接遍历项目:

for result in pool.imap_unordered(func_process_application, very_large_dict.iteritems()):

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-07
    • 2021-12-27
    • 2018-04-14
    • 1970-01-01
    • 2012-05-27
    • 1970-01-01
    • 2015-01-17
    • 1970-01-01
    相关资源
    最近更新 更多