numpy数组上的简单多处理

时间:2016-02-21 17:08:01

标签: python arrays numpy python-multiprocessing

我希望使用u ** 2模块加快u multiprocessing的计算速度,其中multi.py是一个numpy数组。

这是我的尝试(文件名# to compile on Windows/Ipython : import multi then run -m multi from multiprocessing import Pool import numpy as np if __name__ == '__main__': u=np.arange(6e7) def test(N): pool = Pool(N) v=len(u)//N tasks = [ u[k*v:(k+1)*v] for k in range(N)] res = pool.map_async(np.square,tasks).get() return res ):

In [25]: %time  r1=test(1)
Wall time: 13.2 s

In [26]: %time  r2=test(2)
Wall time: 7.75 s

In [27]: %time  r4=test(4)
Wall time: 8.29 s

In [31]: %time r=u**2
Wall time: 512 ms

以下是基准:

u ** 2

我的PC上有2个物理内核,因此测试(2)比测试(1)运行得更快是令人鼓舞的。

但目前,numpy更快。多处理增加了大的过载。

所以我的问题是:multiprocessing如何(或可能)加快//This span is used to measure the size of the textarea //it should have the same font and text with the textarea and should be hidden var span = $('<span>').css('display','inline-block') .css('word-break','break-all') .appendTo('body').css('visibility','hidden'); function initSpan(textarea){ span.text(textarea.text()) .width(textarea.width()) .css('font',textarea.css('font')); } $('textarea').on({ input: function(){ var text = $(this).val(); span.text(text); $(this).height(text ? span.height() : '1.1em'); }, focus: function(){ initSpan($(this)); }, }); 的速度?

修改

我意识到所有过程工作都是在他自己的内存空间中完成的,因此必然会产生大量的副本(See here for example)。因此没有希望通过这种方式加快简单计算。

2 个答案:

答案 0 :(得分:2)

由于Global Interpreter Lock,CPython中的多处理本身成本很高,这可以防止多个本机线程同时执行相同的Python字节码。 multiprocessing通过为每个工作进程生成一个单独的Python解释器,并使用pickling来发送参数并从工作者返回变量来解决这个限制。不幸的是,这需要很多不可避免的开销。

如果你绝对必须使用multiprocessing,建议尽可能多地对每个进程进行一次工作,以尽量减少产生和杀死的相对时间流程。例如,如果您正在并行处理较大阵列的块,则使块尽可能大,并且可以一次执行尽可能多的处理步骤,而不是多次循环遍历阵列。 / p>

但是,一般情况下,使用不受GIL限制的低级语言进行多线程处理会更好。对于简单的数值表达式,例如你的例子,numexpr是一种非常简单的方法来实现显着的性能提升(~4倍,在具有4核和超线程的i7 CPU上)。除了在C ++中实现并行处理之外,更重要的好处是它避免为中间结果分配内存,从而更有效地使用缓存。

In [1]: import numexpr as ne

In [2]: u = np.arange(6e7)

In [3]: %%timeit u = np.arange(6e7)
   .....: u**2
   .....: 
1 loop, best of 3: 528 ms per loop

In [4]: %%timeit u = np.arange(6e7)
ne.evaluate("u**2")
   .....: 
10 loops, best of 3: 127 ms per loop

适用于更复杂任务的其他选项包括Cythonnumba

最后,我还要提到除了CPython之外还有其他Python实现缺少GIL,例如PyPy,Jython和IronPython。然而,这些都受到其自身的限制。据我所知,他们都没有为numpy,scipy或matplotlib提供适当的支持。

答案 1 :(得分:0)

我自己回答:

来自scipy-cookbook,恕我直言被低估的功能:

  

当numpy正在进行数组操作时,python也会释放GIL。

因此多线程不是numpy操作的问题。

from threading import Thread
import numpy as np

u=np.arange(6*10**7)

def multi(N):
    n=u.size//N 
    threads = [Thread(target=np.ndarray.__ipow__,
               args=(u[k*n:(k+1)*n],2)) for k in range(N)]  
    for t in  threads: t.start()
    for t in  threads: t.join()

在2核处理器上获得近2倍的增益:

In [7]: %timeit test(1)
10 loops, best of 3: 172 ms per loop

In [8]: %timeit test(4)
10 loops, best of 3: 92.7 ms per loop