当前位置: 首页 > 面试题库 >

利用“写时复制”功能将数据复制到Multiprocessing.Pool()工作进程

梁勇
2023-03-14
问题内容

我有multiprocessing一些看起来像这样的Python代码:

import time
from multiprocessing import Pool
import numpy as np

class MyClass(object):
    def __init__(self):
        self.myAttribute = np.zeros(100000000) # basically a big memory struct

    def my_multithreaded_analysis(self):
        arg_lists = [(self, i) for i in range(10)]
        pool = Pool(processes=10)
        result = pool.map(call_method, arg_lists)
        print result

    def analyze(self, i):
        time.sleep(10)
        return i ** 2

def call_method(args):
    my_instance, i = args
    return my_instance.analyze(i)


if __name__ == '__main__':
    my_instance = MyClass()
    my_instance.my_multithreaded_analysis()

在阅读了有关内存在其他StackOverflow答案中的工作方式的答案(例如该Python多处理内存使用情况)后,我的印象是,这种内存使用方式与我用于多处理的进程数量成比例,因为它是写时复制和我尚未修改的任何属性my_instance。但是,运行顶部时,我确实会看到所有进程的高内存,它表示我的大多数进程正在使用大量内存(这是OSX的最高输出,但是我可以在Linux上复制)。

我的问题基本上是,我的解释MyClass实际上在整个池中重复了吗,我是否正确地解释了这一点?如果是这样,我该如何预防呢?我应该不使用这样的结构吗?我的目标是减少用于计算分析的内存使用量。

PID   COMMAND      %CPU  TIME     #TH    #WQ  #PORT MEM    PURG   CMPRS  PGRP PPID STATE
2494  Python       0.0   00:01.75 1      0    7     765M   0B     0B     2484 2484 sleeping
2493  Python       0.0   00:01.85 1      0    7     765M   0B     0B     2484 2484 sleeping
2492  Python       0.0   00:01.86 1      0    7     765M   0B     0B     2484 2484 sleeping
2491  Python       0.0   00:01.83 1      0    7     765M   0B     0B     2484 2484 sleeping
2490  Python       0.0   00:01.87 1      0    7     765M   0B     0B     2484 2484 sleeping
2489  Python       0.0   00:01.79 1      0    7     167M   0B     597M   2484 2484 sleeping
2488  Python       0.0   00:01.77 1      0    7     10M    0B     755M   2484 2484 sleeping
2487  Python       0.0   00:01.75 1      0    7     8724K  0B     756M   2484 2484 sleeping
2486  Python       0.0   00:01.78 1      0    7     9968K  0B     755M   2484 2484 sleeping
2485  Python       0.0   00:01.74 1      0    7     171M   0B     594M   2484 2484 sleeping
2484  Python       0.1   00:16.43 4      0    18    775M   0B     12K    2484 2235 sleeping

问题答案:

发送到pool.map(以及相关方法)的所有内容实际上都没有使用共享的写时复制资源。这些值被“
pickled”(Python的序列化机制)
,通过管道发送到工作进程,然后在其中取消pick,从而从头开始在子进程中重建对象。因此,在这种情况下,每个孩子最终都会得到原始数据的写时复制版本(它从未使用过,因为被告知要使用通过IPC发送的副本),并且个人重新获得了原始数据。在孩子中重建,不共享。

如果要利用分叉的写时复制优势,则不能通过管道发送数据(或引用数据的对象)。您必须将它们存储在可以通过访问其自己的全局变量从孩子那里找到的位置。因此,例如:

import time
from multiprocessing import Pool
import numpy as np

class MyClass(object):
    def __init__(self):
        self.myAttribute = np.zeros(100000000) # basically a big memory struct

    def my_multithreaded_analysis(self):
        arg_lists = list(range(10))  # Don't pass self
        pool = Pool(processes=10)
        result = pool.map(call_method, arg_lists)
        print result

    def analyze(self, i):
        time.sleep(10)
        return i ** 2

def call_method(i):
    # Implicitly use global copy of my_instance, not one passed as an argument
    return my_instance.analyze(i)

# Constructed globally and unconditionally, so the instance exists
# prior to forking in commonly accessible location
my_instance = MyClass()


if __name__ == '__main__':
    my_instance.my_multithreaded_analysis()

通过不传递self,可以避免进行复制,而仅使用写时复制映射到子对象的单个全局对象。如果需要多个对象,则可以在创建池之前对对象的实例进行全局listdict映射,然后将可以将对象作为参数的一部分的索引或键传递给pool.map。然后,worker函数使用索引/键(必须通过IPC对其进行腌制并将其发送给子代)在全局dict(还包括写时复制映射)中查找值(写时复制映射),因此,您可以复制便宜的信息以在孩子中查找昂贵的数据而不进行复制。

如果对象很小,即使您不对其进行写操作,它们也将最终被复制。
CPython被引用计数,并且引用计数出现在公共对象标头中,并且仅通过引用该对象就可以不断更新,即使它是逻辑上不变的引用。因此,将写入并复制小对象(以及分配在同一页内存中的所有其他对象)。对于大型对象(一亿个元素的numpy数组),只要您不对其进行写操作,大部分内容将保持共享状态,因为标头仅占据许多页面之一



 类似资料:
  • 我附加了一个示例谷歌表格数据(链接)。 它包含两张纸。表包含谷歌表单的响应。由于Google表单有很多重复的问题,我必须使用查询功能(sheetcell B2)转换数据。查询命令是 但是,当您查看转换后的工作表时,F列中的一些数据(对应于工作表B列)没有被传输。这个问题怎么解决? 提前感谢

  • 所以在问这个之前,我搜索并发现了一些与我在这里想要做的相似的事情。 基本上我有工作簿AlphaMaster。这个工作簿是一个模板,我想用它来创建每周的新工作簿。 在本工作簿中,有名为“周一至周六”的工作表,以及带有相应日期的周一、周二等其他工作表。 我创建了一个在打开工作簿时加载的表单。我想要的是当我单击表单运行时,它将: > 将代码保存模板作为新工作簿运行 根据userform1的输入重命名工作

  • 本文向大家介绍python利用os模块编写文件复制功能——copy()函数用法,包括了python利用os模块编写文件复制功能——copy()函数用法的使用技巧和注意事项,需要的朋友参考一下 我就废话不多说了,大家还是直接看代码吧~ 补充知识:python复制文件夹(包含os库多种函数的) 看代码吧~ 以上这篇python利用os模块编写文件复制功能——copy()函数用法就是小编分享给大家的全部

  • 所以在COL D中,我必须只粘贴COL A和COL C相等的值,如果这些值不相等,则跳过或粘贴COL D中的任何东西 我写过类似这样的代码,但不幸的是它粘贴了一切!!

  • 2,3和6-12被跳过。下面是我的代码: 我认为这个问题与行“wb1.sheets(1).Range(”a“&Range(”a1“).end(xlDown).row+1)”有关,但我不知道如何解决这个问题。有什么建议吗?谢谢!

  • 本文向大家介绍JS实现复制功能,包括了JS实现复制功能的使用技巧和注意事项,需要的朋友参考一下 效果图: 代码如下: 以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持呐喊教程!