- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一些 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 multiprocessing memory usage我的印象是,这不会根据我用于多处理的进程数来使用内存,因为它是写时复制的,而且我没有修改 my_instance
的任何属性。但是,当我运行 top 时,我确实看到了所有进程的高内存,它说我的大部分进程都在使用大量内存(这是 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's serialization mechanism) ,通过管道发送到工作进程并在那里进行 unpickled,从头开始重建子进程中的对象。因此,在这种情况下,每个 child 最终都会得到原始数据的写时复制版本(它从不使用它,因为它被告知使用通过 IPC 发送的副本),以及对原始数据的个人重建在 child 中重建,不共享。
如果您想利用 fork 的写时复制优势,您不能通过管道发送数据(或引用数据的对象)。您必须将它们存储在可以通过访问他们自己的全局变量从 child 那里找到的位置。例如:
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
或 dict
映射到对象的实例,然后传递可以在 pool.map
的参数中查找对象。 worker 函数然后使用索引/键(必须被 pickle 并通过 IPC 发送给 child )在全局字典(也是写时复制映射)中查找值(写时复制映射),所以你复制便宜的信息来查找 child 中昂贵的数据而不复制它。
如果对象很小,即使您不写入它们,它们最终也会被复制。 CPython 是引用计数的,引用计数出现在公共(public)对象头中并不断更新,仅通过引用对象,即使它是逻辑上不可变的引用。因此,小对象(以及分配在同一内存页中的所有其他对象)将被写入,并因此被复制。对于大对象(你的亿元素 numpy 数组),只要你不写入它,大部分就会保持共享,因为标题只占用许多页面之一
在 python 版本 3.8 中更改:在 macOS 上,spawn 启动方法现在是默认方法。参见 mulitprocessing doc . Spawn 没有利用写时复制。
关于python - 利用 "Copy-on-Write"将数据复制到 Multiprocessing.Pool() 工作进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38084401/
我正在使用 boost.pool,但我不知道何时使用 boost::pool<>::malloc和 boost::pool<>::ordered_malloc ? 所以, boost::pool<>:
我目前正在尝试从 anaconda 中的 spy 控制台运行并行代码。我相信问题可能出在我的计算机不允许 anaconda 控制 CPU 核心上,但我不知道如何解决这个问题。 另一个有趣的点是,当我运
在了解 Python 的 multiprocessing 包(对于 Python 3.4 )时,我注意到 multiprocessing.Pool 是在类 BaseContext 中定义的 上下文.p
我有这样的程序: from multiprocessing import Pool import time def f(x): # I make a heavy code here to take t
我有一个模块 A,它通过获取数据并将其发送到模块 B、C、D 等进行分析,然后将它们的结果结合在一起来执行基本的 map/reduce。 但是模块 B、C、D 等似乎不能自己创建多处理池,否则我得到
所以我有一个脚本可以连接到大约 700 个设备并执行一系列命令,然后退出。我开始使用 Multiprocessing.Pool 和 Pool.map 来减少脚本的运行时间,并允许我同时登录多个设备。
在下面的链接中有对 Pool 类的 map 方法的解释。 它似乎阻塞直到结果准备好。这意味着不需要执行 pool.close(); pool.join() 在运行 pool.map 之后,但是它在 t
context 是 class multiprocessing.pool.Pool 构造函数中的可选参数。 Documentation只说: context can be used to specif
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: What's the difference between sending -release or -dra
不确定这是否是正确的论坛。 libvirt 页面链接在这里。如果这需要张贴在不同的地方请告诉我。 virsh pool-define-as 和 create-as 有什么区别?阅读 virsh 的手册
谁能告诉我Spring Cloud Feign Client是否提供或支持Http连接池,如果可以,那么如何配置诸如池大小的设置?我似乎在官方文档中找不到此内容。谢谢你。 最佳答案 通过调查,我将尝试
我在尝试运行 Flask 应用程序时遇到了一些困难。我收到以下导入错误: File "/db/mysql_utils.py", line 2, in import mysql.conne
我有一个 Node 项目,在其中使用 pg-pool 库。我已在我的依赖项中包含以下内容: "@types/pg-pool": "0.0.3", "pg": "^7.3.0", "pg-format"
在 python 2 中,multiprocessing.dummy.Pool 和 multiprocessing.pool.ThreadPool 之间有什么区别吗?源代码似乎暗示它们是相同的。 最佳
这个问题在这里已经有了答案: Concurrent.futures vs Multiprocessing in Python 3 (6 个答案) 关闭 5 年前。 请给我解释一下这两个类有什么区别?
multiprocessing 的文档states以下关于Pool.join() : Wait for the worker processes to exit. One must call clos
我找到了一些资源,但我不确定我是否理解。 我找到的一些资源是: http://help.sap.com/saphelp_nw70/helpdata/en/fc/eb2ff3358411d1829f00
我的 Javafx 应用程序抛出许多非法状态异常,我尚未能够在源中跟踪触发器。 任何人都可以指导我导致此问题的原因以及我应该在哪里查找原因。我很难在这里展示一些代码,因为我不知道是什么原因造成的。 任
参见下面的示例和执行结果: #!/usr/bin/env python3.4 from multiprocessing import Pool import time import os def in
我目前有一个连接到我的主数据库的开放池,它运行良好。但是现在,我想为另一个数据库打开一个新池。我完全按照设置第一个池的方式设置了新池,显然我编辑了数据库名称等。加载 setupHikari() 方法时
我是一名优秀的程序员,十分优秀!