2

我在python中编写了以下代码

from numba import *

def mul(a, b):
    return a * b

@jit
def numba_mul(a, b):
    return a * b


@jit(int_(int_, int_))
def numba_mul2(a, b):
    return a * b

并得到以下结果

In [3]: %timeit mul(10, 10)
10000000 loops, best of 3: 124 ns per loop

In [4]: %timeit numba_mul(10, 10)
1000000 loops, best of 3: 271 ns per loop

In [5]: %timeit numba_mul2(10, 10)
1000000 loops, best of 3: 263 ns per loop

为什么 CPython 的速度是 Numba 的 2 倍以上?这是在带有 LLVM 3.2 的 OSX 10.9.3 上的 Python 2.7.7 中

如果有帮助,llvm 转储(使用 numba --annotate --llvmp-dump main.py 获得)如下

----------------LLVM DUMP <function descriptor 'numba_mul2$30'>-----------------
; ModuleID = 'module.numba_mul2$30'

define i32 @numba_mul2.int64.int64(i64*, i64 %arg.a, i64 %arg.b) {
entry:
  %a = alloca i64
  store i64 %arg.a, i64* %a
  %b = alloca i64
  store i64 %arg.b, i64* %b
  %a.1 = alloca i64
  %b.1 = alloca i64
  %"$0.1" = alloca i64
  br label %B0

B0:                                               ; preds = %entry
  %1 = load i64* %a
  store i64 %1, i64* %a.1
  %2 = load i64* %b
  store i64 %2, i64* %b.1
  %3 = load i64* %a.1
  %4 = load i64* %b.1
  %5 = mul i64 %3, %4
  store i64 %5, i64* %"$0.1"
  %6 = load i64* %"$0.1"
  store i64 %6, i64* %0
  ret i32 0
}

!python.module = !{!0}

!0 = metadata !{metadata !"__main__"}

================================================================================
-----------------------------------ANNOTATION-----------------------------------
# File: main.py
# --- LINE 30 --- 

@jit(int_(int_, int_))

# --- LINE 31 --- 

def numba_mul2(a, b):

    # --- LINE 32 --- 
    # label 0
    #   a.1 = a  :: int64
    #   b.1 = b  :: int64
    #   $0.1 = a.1 * b.1  :: int64
    #   return $0.1

    return a * b


================================================================================
4

1 回答 1

3

您的测试太小而无法产生有意义的结果。如果您只是执行以下操作:

def f():
    pass
%timeit f()

您可能会得到一个占运行时很大一部分的时间。在我的机器上,使用 mul 函数的时间略多于一半。

此外,numba 必须根据您的参数查找要调度的函数,然后将您的 python 整数转换为 int32/int64,然后创建一个新的 python 对象来包装返回的结果。

在移除盒子/拆箱开销后尝试测试:

from numba import *

def mul(a, b):
    for i in range(1000):
        a * b

@jit
def numba_mul(a, b):
    for i in range(1000):
        a * b


@jit(int_(int_, int_))
def numba_mul2(a, b):
    for i in range(1000):
        a * b
    return a*b

在我的机器上,我分别得到 81.1 µs、330 ns 和 322 ns 的测试时间。

编辑:我很好奇 numba 中空函数调用的开销,所以我添加了以下测试:

def empty(a, b):
    pass

@jit
def numba_empty(a, b):
    pass

@jit
def numba_empty2(a, b):
    numba_empty(a,b)

我在这个测试中得到 155ns、333ns 和 348ns。似乎 numba->numba 调用开销非常小。

于 2014-06-28T21:55:03.983 回答