2012-07-11 68 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