并行化Numpy向量运算

2024-04-29 06:58:22 发布

您现在位置:Python中文网/ 问答频道 /正文

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

还是有更好的办法?


Tags: 数据方法函数代码importnumpy机器利用
3条回答

这里有一个更好的方法: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

文档,包括支持的函数here。你必须检查或者给我们更多的信息,看看你更复杂的函数是否能被numexpr计算。

如果您运行以下命令,这是一个有趣的注意事项:

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函数,还有复制值的开销,默认情况下多处理不共享数据,因此每个值都需要来回复制。

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

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是多线程代码中最好、最安全的方法。。。

我希望这能有帮助。

实际上,SciPy在这个主题上写得很好:http://wiki.scipy.org/ParallelProgramming

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

相关问题 更多 >