python的多处理模块是加速大数值计算的正确方法吗?

时间:2013-07-24 08:33:29

标签: python parallel-processing multiprocessing

我在使用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的优化)?

3 个答案:

答案 0 :(得分:3)

虽然你的问题(在标题中)没有一般性答案,但我认为单独multiprocessing并不是Python中数字运算性能的关键所在。

然而,原则上,Python(+第三方模块)对于数字运算来说非常棒。找到合适的工具,你会感到惊讶。大多数时候,我很确定,在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为此提供了很好的界面。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

根据您提供的测试结果,您似乎在两核计算机上运行测试。我有其中一个并运行您的测试代码获得类似的结果。这些结果表明,运行更多进程的好处远远少于数据应用程序的内核,这些应用程序适用于并行计算。

在我的两台核心机器上,大约20%的CPU被吸收只是为了保持我的环境,所以当我看到运行两个进程的1.8改进时,我确信所有可用的周期都用于我的工作。基本上,对于并行数值工作,核心越多越好,因为这会提高可用于完成工作的计算机的百分比。

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