2

我在使用 FORTRAN 的数值计算和使用 OpenMP 的并行化方面有很强的背景,我发现这很容易在许多问题上使用它。我切换到 PYTHON 是因为它开发起来更有趣(至少对我而言),但数字任务的并行化似乎比 OpenMP 更乏味。我经常有兴趣将大型(数十 GB)数据集加载到主内存并并行操作它,同时在主内存中仅包含数据的单个副本(共享数据)。我开始为此使用 PYTHON 模块 MULTIPROCESSING 并提出了这个通用示例:

#test cases    
#python parallel_python_example.py 1000 1000
#python parallel_python_example.py 10000 50

import sys
import numpy as np
import time
import multiprocessing
import operator

n_dim = int(sys.argv[1])
n_vec = int(sys.argv[2])

#class which contains large dataset and computationally heavy routine
class compute:
    def __init__(self,n_dim,n_vec):
        self.large_matrix=np.random.rand(n_dim,n_dim)#define large random matrix
        self.many_vectors=np.random.rand(n_vec,n_dim)#define many random vectors which are organized in a matrix
    def dot(self,a,b):#dont use numpy to run on single core only!!
        return sum(p*q for p,q in zip(a,b))
    def __call__(self,ii):# use __call__ as computation such that it can be handled by multiprocessing (pickle)
        vector = self.dot(self.large_matrix,self.many_vectors[ii,:])#compute product of one of the vectors and the matrix
        return self.dot(vector,vector)# return "length" of the result vector

#initialize data
comp = compute(n_dim,n_vec)

#single core
tt=time.time()
result = [comp(ii) for ii in range(n_vec)]
time_single = time.time()-tt
print "Time:",time_single

#multi core
for prc in [1,2,4,10]:#the 20 case is there to check that the large_matrix is only once in the main memory
  tt=time.time()
  pool = multiprocessing.Pool(processes=prc)
  result = pool.map(comp,range(n_vec))
  pool.terminate()
  time_multi = time.time()-tt  
print "Time using %2i processes. Time: %10.5f, Speedup:%10.5f" % (prc,time_multi,time_single/time_multi)

我在我的机器(使用 Fedora 18 的 64 位 Linux)上运行了两个测试用例,结果如下:

andre@lot:python>python parallel_python_example.py 10000 50
Time: 10.3667809963
Time using  1 processes. Time:   15.75869, Speedup:   0.65785
Time using  2 processes. Time:   11.62338, Speedup:   0.89189
Time using  4 processes. Time:   15.13109, Speedup:   0.68513
Time using 10 processes. Time:   31.31193, Speedup:   0.33108
andre@lot:python>python parallel_python_example.py 1000 1000
Time: 4.9363951683
Time using  1 processes. Time:    5.14456, Speedup:   0.95954
Time using  2 processes. Time:    2.81755, Speedup:   1.75201
Time using  4 processes. Time:    1.64475, Speedup:   3.00131
Time using 10 processes. Time:    1.60147, Speedup:   3.08242

我的问题是,我在这里误用了 MULTIPROCESSING 模块吗?或者这是它与 PYTHON 一起使用的方式(即不在 python 中并行化,而是完全依赖于 numpy 的优化)?

4

3 回答 3

3

虽然您的问题没有一般性的答案(在标题中),但我认为可以说multiprocessing仅凭这一点并不是 Python 中出色的数字处理性能的关键。

然而,原则上,Python(+ 3rd 方模块)非常适合数字运算。找到合适的工具,你会感到惊讶。大多数时候,我很确定,与在 Fortran 中手动执行所有操作之前相比,编写(很多!)更少的代码可以获得更好的性能。您只需要使用正确的工具和方法。这是一个广泛的话题。一些您可能感兴趣的随机事物:

  • 您可以使用英特尔 MKL 和 OpenMP 自己编译 numpy 和 scipy(或者您设施中的系统管理员可能已经这样做了)。这样,许多线性代数运算将自动使用多个线程并充分利用您的机器。这简直太棒了,到目前为止可能被低估了。掌握正确编译的 numpy 和 scipy!

  • multiprocessing应该被理解为管理多个或多或少独立进程的有用工具。这些进程之间的通信必须明确编程。通信主要通过管道进行。相互交谈的进程大部分时间都在交谈,而不是数字运算。因此,multiprocessing最好在输入和输出数据的传输时间小于计算时间的情况下使用。还有一些技巧,例如,您可以利用 Linux 的fork()行为并在多个进程之间共享大量内存(只读!),multiprocessing而无需通过管道传递这些数据。您可能想看看https://stackoverflow.com/a/17786444/145400

  • 前面已经提到过 Cython,您可以在特殊情况下使用它,并将 Python 程序中的性能关键代码部分替换为编译后的代码。

我没有评论您的代码的细节,因为(a)它不是很可读(请在编写 Python 代码时习惯PEP8 :-))和(b)我认为特别是关于数字运算这取决于问题是什么正确的解决方案是。您已经在基准测试中观察到我上面概述的内容:在 的上下文中multiprocessing,关注通信开销尤为重要。

一般来说,您应该始终尝试从 Python 中找到一种方法来控制已编译的代码来为您完成繁重的工作。Numpy 和 SciPy 为此提供了很好的接口。

于 2013-07-24T09:45:03.690 回答
0

用 Python 处理数字......您可能应该了解Cython。它是 Python 和 C 之间的中间语言。它与 numpy 紧密连接,并支持使用 openMP 作为后端的并行化。

于 2013-07-24T08:43:35.993 回答
0

从您提供的测试结果来看,您似乎在两核机器上运行了测试。我有其中之一,并运行了您的测试代码,得到了类似的结果。这些结果表明,运行更多的进程并没有什么好处比你拥有适合并行计算的数值应用程序的核心。

在我的两核机器上,大约 20% 的 CPU 仅用于维持我的环境运行,因此当我看到运行两个进程的 1.8 改进时,我确信所有可用周期都用于我的工作。基本上,对于并行数值工作,内核越多越好,因为这会提高可用于工作的计算机的百分比。

其他海报完全正确地将您指向 Numpy、Scipy、Cython 等。基本上,您首先需要使您的计算使用尽可能少的周期,然后以某种形式使用多处理来找到更多周期来解决您的问题。

于 2013-07-24T11:51:39.743 回答