OpenMP 和 Python
Posted
技术标签:
【中文标题】OpenMP 和 Python【英文标题】:OpenMP and Python 【发布时间】:2012-07-07 06:48:06 【问题描述】:我有为共享内存机器(在 C 和 FORTRAN 中)编写 OpenMP 以执行矩阵加法、乘法等简单任务的经验(只是想看看它如何与 LAPACK 竞争)。我对 OpenMP 的了解足以执行简单的任务,而无需查看文档。
最近,我为我的项目转向 Python,除了绝对基础之外,我没有任何 Python 经验。
我的问题是:
在 Python 中使用 OpenMP最简单的方法是什么?最简单的意思是在程序员方面花费最少的努力(即使它以增加系统时间为代价)?
我使用 OpenMP 的原因是因为串行代码可以转换为工作并行代码,其中散布着一些 !$OMP
s。实现粗略并行化所需的时间非常短。有没有办法在 Python 中复制此功能?
通过浏览 SO,我可以找到:
C 扩展 无堆栈 Python还有更多吗?哪个最符合我的问题?
【问题讨论】:
【参考方案1】:由于 GIL,在 CPython 中将线程用于 CPU 密集型任务毫无意义。您需要多处理 (example) 或使用在计算期间释放 GIL 的 C 扩展,例如,一些 numpy 函数,example。
您可以在 Cython 中轻松编写使用多线程的 C 扩展,example。
【讨论】:
在 Python 中ctypes
上的任何 cmets(常规)?
@Inquest:ctypes 允许您在纯 Python 中从 C 库中调用几个函数
是的,我知道这一点。我正在向你们的 cmets 征求关于在 Python 中使用 ctypes 进行并行编程的可行性。
@Inquest ctypes 只有在基本上所有工作都在 C 函数中完成的情况下才真正有助于并行化,并且您的 python 只是调用它们的包装器。这并不是真正的“Python 中的并行编程”,但它有时很方便。
ctypes
让您可以访问 C 中的共享内存。因此它对于并行编程非常有用,因为如果您有需要在进程之间共享的大数据,它可以显着提高速度。 multiprocessing
和其他 python 模块具有通过ctypes
利用共享内存的方法【参考方案2】:
据我所知,没有适用于 Python 的 OpenMP 包(我不知道如果有它会做什么)。如果您希望线程直接在您的控制之下,您将不得不使用其中一个线程库。然而,正如其他人所指出的,GIL(全局解释器锁)使 Python 中的多线程性能有点……好吧,毫无意义*。 GIL 意味着一次只有一个线程可以访问解释器。
我建议改为查看 NumPy/SciPy。 NumPy 允许您编写 Matlab 式代码,您可以在其中通过单个操作对数组和矩阵进行操作。它还具有一些并行处理能力,请参阅SciPy Wiki。
其他开始寻找的地方:
Experiences Making CPU Bound Tasks Much Faster Speeding up Python (NumPy, Cython and Weave)* 好吧,这不是毫无意义的,但除非时间消耗在 Python 代码之外(例如通过popen
或类似调用的外部进程),否则线程不会给你买任何东西方便。
【讨论】:
所以你甚至不能编译openmp c代码并从python调用二进制文件?为什么这不起作用 @MySchizoBuddy - 是的,您可以编写 OpenMP C 代码,编译并从 Python 调用它。这在 GIL 的范围之外执行,因为它不是由 Python 引擎执行的。但是,在 Python 中没有 直接 方式使用 OpenMP。 是 ipython 中使用的“map reduce”,是一种可接受的替代方案,尽管它主要是为大数据设计的 map reduce 是一种函数式编程概念,您可以在其中获取数据并将每个数据映射到一个函数,然后对函数的结果进行归约(例如求和它们的答案)。 MapReduce 大数据范式将数据映射到对这些数据执行某些操作的多个工作进程。然后减少数据以提供答案。 MapReduce 最大的优势在于它的约束简化了代码并行化的过程。挑战在于分解您的问题以适应 MapReduce 约束。如果 iPython 有一个分布式 MapReduce,您可以从中获得并行性,但它需要工作。【参考方案3】:如果你想发布 GIL 并使用 OpenMP ypu 可以看看 Cython。它为一些常见任务提供了简单的并行性。您可以在 Cython documentation 阅读更多内容。
【讨论】:
【参考方案4】:也许您的回复是在 Cython 中:
“Cython 通过 cython.parallel 模块支持本机并行性。要使用这种并行性,必须释放 GIL(请参阅释放 GIL)。它目前支持 OpenMP,但以后可能会支持更多后端。” Cython Documentation
【讨论】:
带有 openmp 的 cython 在多核 cpu 上非常棒,与单线程相比,我在 8 核机器上获得了 700% 的加速【参考方案5】:http://archive.euroscipy.org/talk/6857“介绍了 Cython 的 OpenMP 功能,专注于 NumPy 数组上的并行循环。源代码示例演示了如何在 Python 中使用 OpenMP。OpenMP 并行算法的结果显示了与不同数据大小相比,可以实现哪些加速其他并行化策略。”
import numpy
import cython
from cython cimport parallel
@cython.boundscheck(False)
@cython.wraparound(False)
def func(object[double, ndim=2] buf1 not None,
object[double, ndim=2] buf2 not None,
object[double, ndim=2] output=None,
int num_threads=2):
cdef unsigned int x, y, inner, outer
if buf1.shape != buf2.shape:
raise TypeError('Arrays have different shapes: %s, %s' % (buf1.shape,
buf2.shape))
if output is None:
output = numpy.empty_like(buf1)
outer = buf1.shape[0]
inner = buf1.shape[1]
with nogil, cython.boundscheck(False), cython.wraparound(False):
for x in parallel.prange(outer, schedule='static',
num_threads=num_threads):
for y in xrange(inner):
output[x, y] = ((buf1[x, y] + buf2[x, y]) * 2 +
buf1[x, y] * buf2[x, y])
return output
【讨论】:
【参考方案6】:赛通
Cython 具有 OpenMP 支持:使用 Cython,可以通过使用 prange
(并行范围)运算符并添加 -fopenmp
编译器指令来设置 OpenMP .py.
在 prange 节中工作时,执行是并行执行的,因为我们通过使用 with nogil:
指定禁用 GIL 的块来禁用 全局解释器锁 (GIL)。 p>
要编译 cython_np.pyx,我们必须修改 setup.py 脚本,如下所示。我们告诉它通知 C 编译器在编译期间使用 -fopenmp
作为参数 - 以启用 OpenMP 并与 OpenMP 库链接。
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = "build_ext": build_ext,
ext_modules = [
Extension(
"calculate",
["cython_np.pyx"],
extra_compile_args = ["-fopenmp"],
extra_link_args = ["-fopenmp"]
)
]
)
使用 Cython 的 prange,
,我们可以选择不同的调度方法。使用 static, 工作负载均匀分布在可用的 CPU 上。但是,由于您的一些计算区域在时间上很昂贵,而另一些则很便宜 - 如果我们要求 Cython 在 CPU 上使用 static 平均调度工作块,那么某些区域的结果将更快地完成比其他线程,然后这些线程将处于空闲状态。
dynamic 和 guided 调度选项都试图通过在运行时动态分配较小块的工作来缓解此问题,以便在工作负载的计算时间可变时 CPU 分布更均匀.因此,对于您的代码,正确的选择将取决于您的工作负载的性质。
麻木
Numba 的高级版本 NumbaPro 具有对 prange
并行化运算符的实验性支持,可与 OpenMP 一起使用。
Pythran
Pythran(Python 子集的 Python 到 C++ 编译器)可以利用矢量化可能性和基于 OpenMP 的并行化可能性,尽管它仅使用 Python 2.7 运行。您可以使用 pragma omp
指令指定并行部分(非常类似于上述 Cython 的 OpenMP 支持),例如:
PyPy
>JIT Python 编译器 PyPy 支持多处理模块(见下文),并有一个名为 PyPy-STM "a special in-development version of PyPy which can run multiple independent CPU-hungry threads in the same process in parallel" 的项目。
旁注:多处理
OpenMP 是多核的低级接口。您可能想查看multiprocessing.
multiprocessing
模块在更高级别上工作,共享 Python 数据结构,而 OpenMP 在您编译为 C 后与 C 原始对象(例如,整数和浮点数)一起工作。它只会使如果你正在编译你的代码,那么使用 OpenMP 是有意义的;如果您不进行编译(例如,如果您使用高效的 numpy 代码并且希望在多个内核上运行),那么坚持使用 multiprocessing
可能是正确的方法。
【讨论】:
这是最完整的答案。谢谢! @boardrider ,你能更新一下这个答案吗?这会很棒,因为它确实具有解释性和广泛性。谢谢【参考方案7】:有一个名为pymp 的包,作者将其描述为为Python 带来类似OpenMP 的功能的包。我尝试过使用它,但有不同的用例:文件处理。有效。我认为使用起来非常简单。 以下是取自 GitHub 页面的示例:
import pymp
ex_array = pymp.shared.array((100,), dtype='uint8')
with pymp.Parallel(4) as p:
for index in p.range(0, 100):
ex_array[index] = 1
# The parallel print function takes care of asynchronous output.
p.print('Yay! done!'.format(index))
【讨论】:
以上是关于OpenMP 和 Python的主要内容,如果未能解决你的问题,请参考以下文章