2012-07-11 67 views
36

让我们使用,例如,numpy.sin()并行化numpy的矢量运算

下面的代码将返回正弦的值的阵列a的每个值:

import numpy 
a = numpy.arange(1000000) 
result = numpy.sin(a) 

但是我的机具有32个内核,所以我想利用它们。 (对于像numpy.sin()之类的东西,开销可能不值得,但是我实际上想要使用的功能相当复杂一些,并且我将使用大量的数据。)

这是最好的(阅读:最聪明或最快)方法:

from multiprocessing import Pool 
if __name__ == '__main__': 
    pool = Pool() 
    result = pool.map(numpy.sin, a) 

还是有更好的方法来做到这一点?

+0

如果你打算使用'pool.map()',你应该使用'math.sin',因为它比'numpy.sin'更快。参考:http://stackoverflow.com/questions/3650194/are-numpys-math-functions-faster-than-pythons。 – EOL 2014-01-06 19:53:29

+2

对于'numpy.sin',[官方numpy/scipy wiki](http://wiki.scipy.org/ParallelProgramming)表示,如果你[用openmp编译numpy开启]它应该并行工作(https:// software.intel.com/en-us/articles/numpyscipy-with-intel-mkl)。 – ziyuang 2015-02-18 14:31:29

+0

你也可以使用[Bohrium](http://bohrium.readthedocs.io/):它应该像用'import bohrium as numpy'替换你的第一行一样简单...... – j08lue 2016-05-04 09:33:22

回答

48

一个更好的办法:numexpr

略从他们的主页改写:

这是一个多线程的虚拟机用C写的,分析的表达,更有效地改写他们,并编译它们飞入代码,获得接近最佳并行性能的内存和cpu有界操作。

例如,在我的4核心机器中,评估一个正弦比numpy略快四倍。

In [1]: import numpy as np 
In [2]: import numexpr as ne 
In [3]: a = np.arange(1000000) 
In [4]: timeit ne.evaluate('sin(a)') 
100 loops, best of 3: 15.6 ms per loop  
In [5]: timeit np.sin(a) 
10 loops, best of 3: 54 ms per loop 

文档,包括支持的函数here。你必须检查或给我们更多的信息,看看你的更复杂的功能可以通过numexpr来评估。

+4

我写了我的代码使用numexpr,它执行的速度比相同的代码快6倍左右numpy的。非常感谢您的建议!现在我想知道为什么numexpr不是更普遍。在我用Python搜索数字包的过程中,我至今还没有遇到过。 numexpr中还有一些小小的烦恼,不支持数组索引,但这并不是一个挫折。 – user1475412 2012-07-16 02:15:42

+1

也许你还应该检查Theano和Cython。 Theano可以使用GPU,但我没有真正使用过,因此我无法为您提供示例。 – jorgeca 2012-07-16 14:38:49

+2

为什么numexpr不是更普遍的一个原因是我认为这比使用纯NumPy更麻烦(比如上面的例子)。不过,这对于轻松加速NumPy计算的速度确实非常重要。 – EOL 2015-08-17 11:11:18

17

嗯,这是一种有趣的注意,如果你运行下面的命令:

import numpy 
from multiprocessing import Pool 
a = numpy.arange(1000000)  
pool = Pool(processes = 5) 
result = pool.map(numpy.sin, a) 

UnpicklingError: NEWOBJ class argument has NULL tp_new 

没想到的是,有啥继续,以及:

>>> help(numpy.sin) 
    Help on ufunc object: 

sin = class ufunc(__builtin__.object) 
| Functions that operate element by element on whole arrays. 
| 
| To see the documentation for a specific ufunc, use np.info(). For 
| example, np.info(np.sin). Because ufuncs are written in C 
| (for speed) and linked into Python with NumPy's ufunc facility, 
| Python's help() function finds this page whenever help() is called 
| on a ufunc. 

yep numpy.sin在c中实现,因此您不能直接在多处理中使用它。

,所以我们有另一个函数把它包起来

PERF:

import time 
import numpy 
from multiprocessing import Pool 

def numpy_sin(value): 
    return numpy.sin(value) 

a = numpy.arange(1000000) 
pool = Pool(processes = 5) 

start = time.time() 
result = numpy.sin(a) 
end = time.time() 
print 'Singled threaded %f' % (end - start) 
start = time.time() 
result = pool.map(numpy_sin, a) 
pool.close() 
pool.join() 
end = time.time() 
print 'Multithreaded %f' % (end - start) 


$ python perf.py 
Singled threaded 0.032201 
Multithreaded 10.550432 

哇,没想到,要么,我们甚至使用python的功能以及那里有对于初学者几个问题如果它只是一个包装器与一个纯c函数,并且也是复制值的开销,那么默认情况下多处理器不会共享数据,因为每个值都需要前后复制。

也指出,如果得到适当的细分我们的数据:

import time 
import numpy 
from multiprocessing import Pool 

def numpy_sin(value): 
    return numpy.sin(value) 

a = [numpy.arange(100000) for _ in xrange(10)] 
pool = Pool(processes = 5) 

start = time.time() 
result = numpy.sin(a) 
end = time.time() 
print 'Singled threaded %f' % (end - start) 
start = time.time() 
result = pool.map(numpy_sin, a) 
pool.close() 
pool.join() 
end = time.time() 
print 'Multithreaded %f' % (end - start) 

$ python perf.py 
Singled threaded 0.150192 
Multithreaded 0.055083 

那么,我们能从这个取,多是伟大的,但我们应该始终测试,有时比较一下它的速度更快,有时它更慢,取决于如何其使用...

授予您没有使用numpy.sin但另一个函数我建议您首先验证确实多处理会加快计算速度,也许前后复制值的开销可能会影响到您。

无论哪种方式,我还认为,使用pool.map是多线程代码是最好的,最安全的方法...

我希望这有助于。

+0

非常感谢!这是非常丰富的。根据我所读的内容,我假定'Pool'的map()函数对数据有一定的智能性,但我认为首先对它进行细分会产生巨大的影响。有没有其他方法可以避免进程复制数据的开销?如果我使用'math.sin()'代替,你期望有任何性能差异吗? – user1475412 2012-07-11 23:46:26

+0

我实际上试过'math.sin',它的速度慢很多,甚至多线程,然后是单线程numpy.sin,虽然速度更快(采用'6.435199'比采用'10.5'的多线程'numpy.sin',可能由于'numpy.sin'可以处理数组,'numpy'家伙的数学真的很棒;)是的,有一种使用'shared memory'的方法http://docs.python.org/library/multiprocessing .html但请不要使用它相当危险并且支持有限,或者至少要小心行事。 – 2012-07-11 23:53:05

+0

如果你只在做读取然后它可能是安全的,子进程只需要跟踪其相应的索引或索引的子集... – 2012-07-11 23:58:12