并行化Numpyvector操作

让我们使用,例如, numpy.sin()

以下代码将返回数组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 ) 

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

有一个更好的方法: numexpr

稍微从他们的主页重写:

这是一个使用C语言编写的multithreading虚拟机,它可以分析expression式,更有效地重写它们,并将它们编译成接近最佳并行性能的代码,用于内存和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 

文档,包括支持的function在这里 。 你必须检查或给我们更多的信息,看看你的更复杂的function可以通过numexpr来评估。

那么如果你运行下面的命令,这是一个有趣的logging:

 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函数,也是复制值的开销,默认多处理不' t共享数据,因此每个值都需要被来回复制。

请注意,如果正确分段我们的数据:

 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 

那么我们可以从中得到什么,多处理是伟大的,但我们应该总是testing和比较它有时更快,有时更慢,取决于它的使用方式…

当然你并没有使用numpy.sin但是我build议你先确认一下,确实多处理会加快计算速度,也许前后复制值的开销会影响到你。

无论哪种方式,我也相信 ,使用pool.map是multithreading代码最好,最安全的方法…

我希望这有帮助。

SciPy实际上在这个主题上有一个很好的写法: http ://wiki.scipy.org/ParallelProgramming