2017-12-06 22 views
3

は、それらの実行タイミングと同じ整数入力 Numba Cythonループ最適化VS

def python(n): 
    total = 0 
    for m in range(1,n+1): 
     total += m 
    return total 

from numba import jit 
numba = jit(python) 

cpdef int cython(int n): 
    cdef int total = 0 
    cdef int m 
    for m in range(1, n+1): 
     total += m 
    return total 

def smart(n): 
    return n * (n + 1) // 2 

が与えられたとき私は発見し幾分驚いた同じ応答を計算し、次の4つの機能( pythonnumbacythonsmart)を考えます

  1. numbaのランタイムはnとは無関係である(cythonながら 'sはnに線形である)
  2. numbasmart

これはすぐに二つの質問を提起するより遅いです:

  1. なぜNumbaがあるが、

    ないCython、一定の時間アルゴリズムにそれを回すことができますか?
  2. Numba の場合、contstant-timeアルゴリズムに変換できますが、純粋なPythonの一定時間関数smartより遅いのはなぜですか?

私はアセンブラMavenを午前ないので、生成されたコードを見ると、本当に含有するように(ただし、私が誤解しているかもしれない)Numbaによって生成された中間LLVMのコードがまだ表示されていることを超えて、手がかりの私はあまり与えませんループ...と私は絶望的に最終的にそれから生成されるx64で失われる。 (誰かが聞いていない限り、生成されたコードはかなり長いので投稿しません)

私はこれをx64 LinuxでJupyterノートブックで実行しています。したがって、CythonがGCC 4.4を使用していると思われます。 Pythonをコンパイルするために使用された7。 llvmlite 0.20.0は、LLVM 4.0.xを意味します。

編集:

Iは

smart_numba = jit(smart) 

cpdef int smart_cython(int n): 
    return n * (n + 1) // 2 

smart_numbanumbasmart(純粋パイソン)より 25%遅い同じタイミングを与えるのにもタイミングましたsmart_cythonより175%遅い。

これは、Numbaが貧弱な仕事をしているのに対し、CythonはPython /低レベルの境界を効率的に越えていることを示していますか?それとも何か他にはありますか?

答えて

5
  1. これはLLVM GCC対のもののように見える - numbaが出してくれるものよりも少ないノイジーである、コンパイラエクスプローラhereの例を参照してください。アセンブリでは少し失われますが、GCCの出力にはループ(jge.L6)があり、clangの出力にはループがありません。 GCC bugtrackerのthis issueも参照してください。

  2. 私のマシン(Windows x64)numbaは、smartよりも大幅に遅くはなく、わずか約9nsです。このオーバーヘッドはnumbaの型派遣のメカニズムによるものと思わ - あなたが特定の過負荷を選ぶことによって、それをElideの場合、numba版はここ

が私のタイミングいるのpythonよりも高速である

In [73]: %timeit numba_sum(10000) 
182 ns ± 1.69 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) 

In [74]: %timeit smart(10000) 
171 ns ± 2.26 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) 

# pick out int64 overload 
i64_numba_sum = numba_sum.get_overload((numba.int64,)) 

In [75]: %timeit i64_numba_sum(10000) 
94 ns ± 1.41 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) 
+0

はい、ゴッドボルトはループの不在/存在をかなり明確にします。しかし、私は32ビットであると理解している 'e'で始まるレジスタの使用によって混乱します。 Numbaは 'int64'を間違いなく推論しました。 'int'を' long int'に変更すると、解読能力を超えて、clangの出力が非常に長く複雑になります。興味深いことに、あなたのマシンのnumbaは、スマートより速いです:私の場合、25%**遅い**です。 Numbaは 'numba'のスピードに合わせて' smart'を遅くします( 'numba'が' smart'よりも遅いことを見ても驚くことではありません)。 – jacg

+0

申し訳ありませんが誤って、私は有意に_slower_を意味しませんでした。編集を参照してください、それはタイプディスパッチが実際にはnumbaバージョンのオーバーヘッドを作成するものであるようです。 – chrisb