Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
纯python上的Numba与numpy python上的Numpa_Python_Performance_Numpy_Numba - Fatal编程技术网

纯python上的Numba与numpy python上的Numpa

纯python上的Numba与numpy python上的Numpa,python,performance,numpy,numba,Python,Performance,Numpy,Numba,使用numba比使用纯python生成的程序快得多: 现在看来,纯python上的numba甚至(大多数时候)比numpy python更快,例如 根据numba的说法,在纯python代码上使用的速度比在使用numpy的python代码上使用的速度快。这通常是真的吗?为什么 在本文中,我们解释了为什么纯python上的numba比numpy python更快:numba比numpy看到更多的代码,并且有更多的方法来优化代码,numpy只看到一小部分 这回答了我的问题吗?在使用nump

使用numba比使用纯python生成的程序快得多:

现在看来,纯python上的numba甚至(大多数时候)比numpy python更快,例如

根据numba的说法,在纯python代码上使用的速度比在使用numpy的python代码上使用的速度快。这通常是真的吗?为什么

在本文中,我们解释了为什么纯python上的numba比numpy python更快:numba比numpy看到更多的代码,并且有更多的方法来优化代码,numpy只看到一小部分


这回答了我的问题吗?在使用numpy时,我是否会妨碍numba充分优化代码,因为numba被迫使用numpy例程,而不是找到一种更为优化的方法?我曾希望numba会意识到这一点,如果这是无益的,就不要使用numpy程序。然后它将使用numpy例程,只是这是一个改进(毕竟numpy经过了很好的测试)。毕竟

在回答具体问题之前,让我们先搞清楚一些事情:

    < L> >我只考虑Nopython代码,对象模式代码通常比纯Python/Nuffy等价物慢。
  • 对于这个问题,我将忽略numba GPU的功能——很难将GPU上运行的代码与CPU上运行的代码进行比较
  • 当您在numba函数中调用NumPy函数时,实际上并不是在调用NumPy函数。numba支持的一切都在numba中重新实现。这适用于NumPy函数,也适用于numba中的Python数据类型!因此,numba函数内部和外部的Python/NumPy实现细节可能不同,因为它们是完全不同的函数/类型
  • Numba生成使用LLVM编译的代码。Numba不是魔术,它只是一个优化编译器的包装器,在Numba中内置了一些优化
现在看来,纯python上的numba甚至(大多数时候)比numpy python更快

不,Numba通常比NumPy慢。这取决于你想做什么手术以及如何做。如果处理非常小的数组,或者如果唯一的替代方法是手动迭代数组,那么Numba的速度会更快

在纯python代码上使用的numba比在使用numpy的python代码上使用的速度快。这通常是真的吗?为什么

这取决于代码-可能有更多的情况下,NumPy击败麻木。然而,诀窍是在没有相应的NumPy函数或需要链接大量NumPy函数或使用不理想的NumPy函数的地方应用numba。诀窍是知道什么时候numba实现可能会更快,然后最好不要在numba中使用NumPy函数,因为这样会得到NumPy函数的所有缺点。然而,应用numba需要经验来了解何时如何——很容易意外地编写出非常慢的numba函数

在使用numpy时,我是否会妨碍numba充分优化代码,因为numba被迫使用numpy例程,而不是找到一种更为优化的方法

是的

我曾希望numba会意识到这一点,如果这是无益的,就不要使用numpy程序

不,那不是numba目前的工作方式。Numba只是为LLVM创建要编译的代码。也许这就是numba未来的一个特点(谁知道呢)。目前,如果您自己编写循环和操作并避免在numba函数中调用NumPy函数,numba的性能最好

有一些库使用表达式树,可能会优化非有益的NumPy函数调用,但这些库通常不允许快速手动迭代。例如,
numexpr
可以优化多个链式NumPy函数调用。目前,它要么是快速手动迭代(cython/numba),要么是使用表达式树(numexpr)优化链式NumPy调用。也许在一个图书馆里不可能同时做这两件事——我不知道


Numba和Cython在小型阵列和快速手动迭代阵列方面非常出色。NumPy/SciPy非常棒,因为它们提供了大量复杂的功能,可以完成各种开箱即用的任务。Numexpr非常适合链接多个NumPy函数调用。在某些情况下,Python比这些工具都快


根据我的经验,如果您编写不同的工具,您可以从中获得最佳效果。不要将自己局限于一种工具。

在回答具体问题之前,让我们先了解一些事情:

    < L> >我只考虑Nopython代码,对象模式代码通常比纯Python/Nuffy等价物慢。
  • 对于这个问题,我将忽略numba GPU的功能——很难将GPU上运行的代码与CPU上运行的代码进行比较
  • 当您在numba函数中调用NumPy函数时,实际上并不是在调用NumPy函数。numba支持的一切都在numba中重新实现。这适用于NumPy函数,也适用于numba中的Python数据类型!因此,numba函数内部和外部的Python/NumPy实现细节可能不同,因为它们是完全不同的函数/类型
  • Numba生成使用LLVM编译的代码。Numba不是魔术,它只是一个优化编译器的包装器,在Numba中内置了一些优化
现在看来,纯python上的numba甚至(大多数时候)比numpy python更快

不,Numba通常比NumPy慢。这取决于你想做什么手术以及如何做。如果处理非常小的数组,或者如果唯一的替代方法是手动迭代数组,那么Numba的速度会更快

在纯python代码上使用的numba比在使用numpy的python代码上使用的速度快。这通常是真的吗?为什么

这取决于代码
#only for single-threaded numpy test
import os
os.environ["OMP_NUM_THREADS"] = "1"

import numba as nb
import numpy as np

a=np.random.rand(100_000_000)
b=np.random.rand(100_000_000)
c=np.random.rand(100_000_000)
d=np.random.rand(100_000_000)

#Numpy version
#every expression is evaluated on its own 
#the summation algorithm (Pairwise summation) isn't equivalent to the algorithm I used below
def Test_np(a,b,c,d):
    return np.sum(a+b*2.+c*3.+d*4.)

#The same code, but for Numba (results and performance differ)
@nb.njit(fastmath=False,parallel=True)
def Test_np_nb(a,b,c,d):
    return np.sum(a+b*2.+c*3.+d*4.)

#the summation isn't fused, aprox. the behaiviour of Test_np_nb for 
#single threaded target
@nb.njit(fastmath=False,parallel=True)
def Test_np_nb_eq(a,b,c,d):
    TMP=np.empty(a.shape[0])
    for i in nb.prange(a.shape[0]):
        TMP[i]=a[i]+b[i]*2.+c[i]*3.+d[i]*4.

    res=0.
    for i in nb.prange(a.shape[0]):
        res+=TMP[i]

    return res

#The usual way someone would implement this in Numba
@nb.njit(fastmath=False,parallel=True)
def Test_nb(a,b,c,d):
    res=0.
    for i in nb.prange(a.shape[0]):
        res+=a[i]+b[i]*2.+c[i]*3.+d[i]*4.
    return res
#single-threaded
%timeit res_1=Test_nb(a,b,c,d)
178 ms ± 1.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_2=Test_np(a,b,c,d)
2.72 s ± 118 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_3=Test_np_nb(a,b,c,d)
562 ms ± 5.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_4=Test_np_nb_eq(a,b,c,d)
612 ms ± 6.08 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

#single-threaded
#parallel=True
#nb.parfor.sequential_parfor_lowering = True
%timeit res_1=Test_nb(a,b,c,d)
188 ms ± 5.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit res_3=Test_np_nb(a,b,c,d)
184 ms ± 817 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit res_4=Test_np_nb_eq(a,b,c,d)
185 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

#multi-threaded
%timeit res_1=Test_nb(a,b,c,d)
105 ms ± 3.08 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_2=Test_np(a,b,c,d)
1.78 s ± 75.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_3=Test_np_nb(a,b,c,d)
102 ms ± 686 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_4=Test_np_nb_eq(a,b,c,d)
102 ms ± 1.48 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
#single-threaded
res_1=Test_nb(a,b,c,d)
499977967.27572954
res_2=Test_np(a,b,c,d)
499977967.2756622
res_3=Test_np_nb(a,b,c,d)
499977967.2756614
res_4=Test_np_nb_eq(a,b,c,d)
499977967.2756614

#multi-threaded
res_1=Test_nb(a,b,c,d)
499977967.27572465
res_2=Test_np(a,b,c,d)
499977967.2756622
res_3=Test_np_nb(a,b,c,d)
499977967.27572465
res_4=Test_np_nb_eq(a,b,c,d)
499977967.27572465