我知道有关此主题的几个问题和答案,但尚未找到对此特定问题的满意答案:
什么是对python循环进行简单的共享内存并行化的最简单方法,在该循环中,通过numpy / scipy函数操作numpy数组?
我并不是在寻找最有效的方法,我只是想实现一些简单的实现,当循环不并行运行时,不需要大量重写。就像OpenMP以较低级别的语言实现一样。
我在这方面看到的最好的答案就是这个,但这是一种很笨拙的方法,它要求一个将循环表达为一个带有单个参数的函数,几行共享数组转换为crud,似乎要求从调用了并行函数__main__
,并且在交互式提示(我花了很多时间)上,它似乎不能很好地工作。
借助Python的所有简单性,这真的是使循环并行化的最佳方法吗?真?这对于以OpenMP方式并行化来说是微不足道的。
我辛苦地阅读了多处理模块的不透明文档,却发现它是如此通用,以至于它似乎适用于除简单循环并行化之外的所有内容。我对设置管理器,代理,管道等不感兴趣。我只有一个简单的循环,完全并行,在任务之间没有任何通信。使用MPI并行化这种简单情况似乎有点过头了,更不用说在这种情况下内存效率低下了。
我没有时间去学习大量不同的Python共享内存并行程序包,但是想知道是否有人对此有更多的经验并且可以向我展示一种更简单的方法。请不要建议使用Cython等串行优化技术(我已经使用过),也不要建议使用诸如BLAS的并行numpy
/ scipy函数(我的情况更普遍,更并行)。
使用Cython并行支持:
# asd.pyx
from cython.parallel cimport prange
import numpy as np
def foo():
cdef int i, j, n
x = np.zeros((200, 2000), float)
n = x.shape[0]
for i in prange(n, nogil=True):
with gil:
for j in range(100):
x[i,:] = np.cos(x[i,:])
return x
在2核计算机上:
$ cython asd.pyx
$ gcc -fPIC -fopenmp -shared -o asd.so asd.c -I/usr/include/python2.7
$ export OMP_NUM_THREADS=1
$ time python -c 'import asd; asd.foo()'
real 0m1.548s
user 0m1.442s
sys 0m0.061s
$ export OMP_NUM_THREADS=2
$ time python -c 'import asd; asd.foo()'
real 0m0.602s
user 0m0.826s
sys 0m0.075s
由于np.cos
(像其他ufuncs一样)释放了GIL ,因此这可以并行运行。
如果要交互使用此功能:
# asd.pyxbdl
def make_ext(modname, pyxfilename):
from distutils.extension import Extension
return Extension(name=modname,
sources=[pyxfilename],
extra_link_args=['-fopenmp'],
extra_compile_args=['-fopenmp'])
和(删除asd.so
并asd.c
首先):
>>> import pyximport
>>> pyximport.install(reload_support=True)
>>> import asd
>>> q1 = asd.foo()
# Go to an editor and change asd.pyx
>>> reload(asd)
>>> q2 = asd.foo()
所以是的,在某些情况下,您可以仅使用线程来并行化。OpenMP只是线程的一个高级包装器,因此,此处只需要Cython即可获得更简单的语法。没有Cython,您可以使用threading
模块
—与多处理类似(并且可能更健壮),但是您无需执行任何特殊操作即可将数组声明为共享内存。
但是,并非所有操作都会释放GIL,因此YMMV会提高性能。
***
从其他Stackoverflow答案中刮取的另一个可能有用的链接—
另一个指向多处理的接口:http :
//packages.python.org/joblib/parallel.html
问题内容: 我想在共享内存中使用一个numpy数组,以便与多处理模块一起使用。困难是像numpy数组一样使用它,而不仅仅是ctypes数组。 这将产生如下输出: 可以ctypes方式访问该数组,例如arr[i]说得通。但是,它不是一个numpy数组,因此我无法执行,或。我想一个解决方案是将数组转换为数组。但是(除了无法完成这项工作外),我不相信会再共享它。 对于必须解决的常见问题,似乎将有一个标准
我正在使用python来分析一些大文件,我遇到了内存问题,所以我一直在使用sys.getsizeof()来尝试跟踪使用情况,但是它在Numpy数组中的行为很奇怪。这里有一个例子,涉及到我必须打开的反照率地图: 数据仍然存在,但是对象的大小,一个3600x7200像素的映射,已经从200 Mb变为80字节。我希望我的内存问题结束,把所有的东西都转换成numpy数组,但我觉得这种行为,如果是真的,会在
共享内存是两个或多个进程共享的内存。 但是,为什么我们需要共享内存或其他通信方式呢? 重申一下,每个进程都有自己的地址空间,如果任何进程想要将自己的地址空间的某些信息与其他进程进行通信,那么只能通过IPC(进程间通信)技术进行。 我们已经知道,通信可以在相关或不相关的进程之间进行。 通常,使用管道或命名管道来执行相互关联的进程通信。 可以使用命名管道或通过共享内存和消息队列的常用IPC技术执行无关
共享内存 在消息传递之外,还存在一种广为人知的并发模型,那就是共享内存。其实如果不能共享内存,消息传递也是不能在不同的线程间传递消息,也谈不上在不同的线程间等待和通知了。共享内存是这一切得以发生的基础。如果查看源码,你会发现消息传递的内部实现就是借用了共享内存机制。相对于消息传递而言,共享内存会有更多的竞争,但是不用进行多次拷贝,在某些情况下,也需要考虑使用这种方式来处理。在Rust中,能共享内存
通过查看shmget()的手动页面,我了解到shmget()调用在内存中分配了#个页面,这些页面可以在进程之间共享。 它是否要创建内核内存页,并将其映射到进程的本地地址空间?还是为该段保留了相同的进程内存页,并将为其他附加进程共享相同的内存页? 调用shmget()时,内核将保留一定数量的段/页。 调用shmat()时,保留的段映射到进程的地址空间/页。 当一个新进程附加到同一段时,前面创建的内核