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

2024-04-29

我有一点multiprocessingPython 代码看起来有点像这样:

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 多处理内存使用 https://stackoverflow.com/questions/14749897/python-multiprocessing-memory-usage我的印象是,这不会与我用于多处理的进程数量成比例地使用内存,因为它是写时复制的,并且我没有修改任何属性my_instance。但是,当我运行 top 时,我确实看到所有进程的内存都很高,它表示我的大多数进程正在使用大量内存(这是 OSX 的 top 输出,但我可以在 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的序列化机制) https://docs.python.org/3/library/pickle.html,通过管道发送到工作进程并在那里进行 unpickle,这会从头开始重建子进程中的对象。因此,在这种情况下,每个子进程最终都会得到原始数据的写时复制版本(它从不使用它,因为它被告知要使用通过 IPC 发送的副本),以及原始数据的个人重新创建。在孩子身上重建并且不被共享。

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

import os
import time
from multiprocessing import Pool
import numpy as np

class MyClass(object):
    def __init__(self):
        self.myAttribute = os.urandom(1024*1024*1024) # basically a big memory struct(~1GB size)

    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,您可以避免进行复制,而只需使用写入时复制映射到子对象中的单个全局对象。如果您需要多个对象,您可以创建一个全局对象list or dict在创建池之前映射到对象的实例,然后将可以查找对象的索引或键作为参数的一部分传递给pool.map。然后,工作函数使用索引/键(必须进行腌制并通过 IPC 发送给子进程)在全局字典(也是写入时复制映射)中查找值(写入时复制映射),因此,您可以复制廉价信息来查找子级中昂贵的数据,而无需复制它。

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

python 版本 3.8 中的更改:在 macOS 上,spawn start 方法现在是默认方法。看多处理文档 https://docs.python.org/3/library/multiprocessing.html。 Spawn 没有利用写时复制。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

利用“写入时复制”将数据复制到 Multiprocessing.Pool() 工作进程 的相关文章

随机推荐

  • React textarea 的值是只读的,但需要更新

    我的 React 应用程序中有一个文本区域 其中填充了一个值 我希望更新此文本区域并提交表单以更新数据库中的行
  • 在 iOS 8 中呈现相机权限对话框

    当我的应用程序在 iOS 8 上第一次尝试访问摄像头时 会向用户显示一个摄像头权限对话框 很像 iOS 7 中用于访问麦克风的麦克风对话框 在 iOS 7 中 可以预先调用麦克风权限对话框并查看是否授予了权限 请参阅这个问题 https s
  • 将数据导入 Django 的好方法

    我想定期将数据导入 Django 项目 我需要告诉我的数据提供者我想要以什么格式接收数据 我应该以 Json XML CSV 格式请求吗 在 Django 中通常如何处理这个问题 Django 有一个用于导入数据的完整框架 称为 Fixtu
  • 无法使用 process.ErrorDataReceived c# 获取进程错误输出

    我已经建立了Form我使用了一段时间的应用程序 现在我想捕捉StandardError我的流程及其standartOutput 我查看了答案SO and MSDN https msdn microsoft com en us library
  • jquery 可以操作用 DOM 创建的临时文档吗?

    我想要实现的目标是通过传递一个大的 html 字符串来操作使用 jquery 使用 DOM 创建的文档 考虑以下示例 var doctype document implementation createDocumentType html v
  • 如何在库的上下文中实例化 Spring?

    我正在寻找一个示例 该示例展示了如何在打包在普通旧的 不可执行的 java 库 JAR 中的一组类的上下文中实例化 Spring 容器 这里的核心目的是提供依赖注入 主要用于日志记录 我认为最根本的问题是不可执行的 jar 没有单一的启动点
  • 如何接收在 PHP 中使用“application/octet-stream”发送的 POST 数据?

    这就是我正在处理的事情 我们的一个计划有一个支持表格 用户可以使用它来请求支持 此表单的作用是 它向 PHP 脚本执行 HTTP POST 请求 该脚本应该收集信息并将其转发到支持电子邮件地址 POST 请求包含三个类型的文本字段Conte
  • 如何提取数字(以及比较形容词或范围)

    我正在用 Python 开发两个 NLP 项目 它们都有类似的任务提取数值和比较运算符来自句子 如下所示 greater than 10 weight not more than 200lbs height in 5 7 feets fas
  • 测试 WebApi 控制器时如何生成 Asp.net 用户身份

    我正在使用 Web API 2 在 web api 控制器中我使用过GetUserId使用 Asp net Identity 生成用户 ID 的方法 我必须为该控制器编写 MS 单元测试 如何从测试项目访问用户 ID 我在下面附上了示例代码
  • 从实体框架模型构建数据库架构

    我发现 EF 可以根据现有数据库架构更新模型 然而 我完全从头开始 那我不想建表了rebuild它们位于 EF 模型文件中 有没有一种方法可以绘制模型文件 并自动为我创建 SQL 表 不幸的是 您必须等待 EF 版本 2 这是一个链接 ht
  • HQL 对象命名参数

    我想知道是否可以从 HQL 中名为参数的对象中检索特定列 Example public class Product private int id private Supplier supplier private String name p
  • MDI应用程序中父窗体的问题

    我使用按钮作为容器中的控件 父窗体 当子窗体出现时 父窗体中的控件 按钮 图片 标签 出现在子窗体上并将其覆盖 我看不到子窗体 有谁知道如何防止这种情况 我不想将这些控件设置为 Control Visible false 因为当我最小化子表
  • 使用 Slick String 插值有条件地更新字段

    我有两个Options val name Option String val shared Option Boolean 我想建立一个UPDATE查询那个SET如果上述值是这些字段Some 但如果它们是 则保持不变None 我已经成功地实现
  • 页面内容中 html 实体的 Rspec 测试

    我正在编写一个请求规范 并想测试字符串 Reports Aging Reports 是否存在 如果我直接将字符放入匹配器表达式中 我会收到错误 无效的多字节字符 所以我尝试了以下操作 page should have content Rep
  • 尝试从 Excel 添加附件到电子邮件,但仅知道文件名的第一部分

    我有一个宏 每天用来将自动生成的文件附加到电子邮件中 文件名需要采用某种格式 其中包括日期和时间 并且由于这是自动的 因此只能固有地知道日期 无需手动检查文件 我在用 Attachments Add and format date etc
  • 如何反序列化数组 google-gson 内的数组

    我有这样的 JSON Answers Locale Ru Name Name1 Locale En Name Name2 Locale Ru Name Name3 Locale En Name Name4 正如你所看到的 我的数组里面有数组
  • 当使用客户端函数填充 DOM 时,如何等待从 puppeteer 中的 page.evaluate 函数加载所有图像

    我试图让代码执行等待所有图像加载之前木偶师截屏 当调用 initData 函数时 我的 DOM 会被填充 该函数是在客户端 js 文件中定义的 延迟或超时是一种选择 但我确信必须有一种更有效的方法来做到这一点 async dataObj g
  • C# - 获取 GPU 的总使用百分比

    我正在向我的程序添加一些新功能 这些功能当前通过串行连接将 CPU 使用情况和 RAM 使用情况发送到 Arduino 请参阅this https create arduino cc projecthub thesahilsaluja cp
  • Karate UI 中的 ShadowRoot dom 元素访问问题

    我正在尝试访问 ShadowRoot dom 树元素 但我面临的问题是我无法使用特定的 html 元素来调用 ShadowRoot 因为该元素是动态的 请参见下面的 html 片段 id vaadin text field error 0
  • 利用“写入时复制”将数据复制到 Multiprocessing.Pool() 工作进程

    我有一点multiprocessingPython 代码看起来有点像这样 import time from multiprocessing import Pool import numpy as np class MyClass objec