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 倍以上速いのはなぜですか? これは、OSX 10.9.3 と LLVM 3.2 の 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 オブジェクトを作成する必要があります。

box/unbox のオーバーヘッドを取り除いた後にテストしてみてください:

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 に答える