58

例如,让我们使用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 )

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

4

3 回答 3

69

一个更好的方法:numexpr

从他们的主页稍微改写:

它是一个用 C 语言编写的多线程 VM,可以分析表达式,更有效地重写它们,并将它们即时编译成代码,从而在内存和 CPU 受限操作中获得接近最佳的并行性能。

例如,在我的 4 核机器中,评估正弦的速度仅比 numpy 快 4 倍。

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

文档,包括此处支持的功能。您必须检查或向我们提供更多信息,以查看是否可以通过 numexpr 评估您的更复杂的函数。

于 2012-07-12T20:28:37.763 回答
26

好吧,如果您运行以下命令,这是一种有趣的注释:

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.

是的 numpy.sin 是在 c 中实现的,因此您不能直接将它与多处理一起使用。

所以我们必须用另一个函数包装它

性能:

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

那么我们可以从中得到什么,多处理很棒,但我们应该始终测试和比较它,有时它更快,有时它更慢,这取决于它的使用方式......

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

无论哪种方式,我也相信使用pool.map是多线程代码的最佳,最安全的方法......

我希望这有帮助。

于 2012-07-11T23:17:22.527 回答
11

SciPy 实际上在这里有一篇关于这个主题的很好的文章:http ://wiki.scipy.org/ParallelProgramming

编辑:死链接,现在可以在以下位置找到: http ://scipy-cookbook.readthedocs.io/items/ParallelProgramming.html

于 2012-07-11T22:13:51.043 回答