型付きメモリビューの推奨メモリ割り当て方法は?
質問
その 型付きメモリビューに関するCythonのドキュメント には、型付けされたメモリビューに割り当てる3つの方法が記載されています。
- 生の C ポインタから。
-
から
np.ndarray
と -
から
cython.view.array
.
cython関数に外部からデータを渡さずに、メモリを確保して
np.ndarray
として返したい場合、どのオプションを選べばよいのでしょうか?また、そのバッファのサイズはコンパイル時の定数ではないと仮定してください。
malloc
にする必要があります。
したがって、3つのオプションは次のようになります。
from libc.stdlib cimport malloc, free
cimport numpy as np
from cython cimport view
np.import_array()
def memview_malloc(int N):
cdef int * m = <int *>malloc(N * sizeof(int))
cdef int[::1] b = <int[:N]>m
free(<void *>m)
def memview_ndarray(int N):
cdef int[::1] b = np.empty(N, dtype=np.int32)
def memview_cyarray(int N):
cdef int[::1] b = view.array(shape=(N,), itemsize=sizeof(int), format="i")
意外なのは、この3つのケースで
Cython は非常に多くのコードを生成します。
への呼び出しなど、メモリ割り当てのために非常に多くのコードを生成していることです。
__Pyx_PyObject_to_MemoryviewSlice_dc_int
. これは、最初に Python オブジェクトを作成して、それをメモリ ビューに "casts" することを示唆しています (ここで間違っているかもしれません、私の Cython の内部動作への洞察力は非常に限られています)。
A シンプルなベンチマーク は、3つの方式に大きな違いはなく、2.が僅差で最速でした。
3つの方法のうち、どれが推奨されるのでしょうか?あるいは、他に良い方法があるのでしょうか?
続いての質問です。
私は最終的に結果を
np.ndarray
として最終的に結果を返したい。型付けされたメモリビューが最適なのか、それとも以下のような古いバッファインターフェイスを使って
ndarray
を作成する方がいいのでしょうか?
cdef np.ndarray[DTYPE_t, ndim=1] b = np.empty(N, dtype=np.int32)
どのように解決するのですか?
見てください。 ここで をご覧ください。
基本的な考え方は
cpython.array.array
と
cpython.array.clone
(
ではない
cython.array.*
):
from cpython.array cimport array, clone
# This type is what you want and can be cast to things of
# the "double[:]" syntax, so no problems there
cdef array[double] armv, templatemv
templatemv = array('d')
# This is fast
armv = clone(templatemv, L, False)
EDIT
そのスレッドのベンチマークはゴミだったことが判明しました。これが私のセットで、私のタイミングです。
# cython: language_level=3
# cython: boundscheck=False
# cython: wraparound=False
import time
import sys
from cpython.array cimport array, clone
from cython.view cimport array as cvarray
from libc.stdlib cimport malloc, free
import numpy as numpy
cimport numpy as numpy
cdef int loops
def timefunc(name):
def timedecorator(f):
cdef int L, i
print("Running", name)
for L in [1, 10, 100, 1000, 10000, 100000, 1000000]:
start = time.clock()
f(L)
end = time.clock()
print(format((end-start) / loops * 1e6, "2f"), end=" ")
sys.stdout.flush()
print("μs")
return timedecorator
print()
print("INITIALISATIONS")
loops = 100000
@timefunc("cpython.array buffer")
def _(int L):
cdef int i
cdef array[double] arr, template = array('d')
for i in range(loops):
arr = clone(template, L, False)
# Prevents dead code elimination
str(arr[0])
@timefunc("cpython.array memoryview")
def _(int L):
cdef int i
cdef double[::1] arr
cdef array template = array('d')
for i in range(loops):
arr = clone(template, L, False)
# Prevents dead code elimination
str(arr[0])
@timefunc("cpython.array raw C type")
def _(int L):
cdef int i
cdef array arr, template = array('d')
for i in range(loops):
arr = clone(template, L, False)
# Prevents dead code elimination
str(arr[0])
@timefunc("numpy.empty_like memoryview")
def _(int L):
cdef int i
cdef double[::1] arr
template = numpy.empty((L,), dtype='double')
for i in range(loops):
arr = numpy.empty_like(template)
# Prevents dead code elimination
str(arr[0])
@timefunc("malloc")
def _(int L):
cdef int i
cdef double* arrptr
for i in range(loops):
arrptr = <double*> malloc(sizeof(double) * L)
free(arrptr)
# Prevents dead code elimination
str(arrptr[0])
@timefunc("malloc memoryview")
def _(int L):
cdef int i
cdef double* arrptr
cdef double[::1] arr
for i in range(loops):
arrptr = <double*> malloc(sizeof(double) * L)
arr = <double[:L]>arrptr
free(arrptr)
# Prevents dead code elimination
str(arr[0])
@timefunc("cvarray memoryview")
def _(int L):
cdef int i
cdef double[::1] arr
for i in range(loops):
arr = cvarray((L,),sizeof(double),'d')
# Prevents dead code elimination
str(arr[0])
print()
print("ITERATING")
loops = 1000
@timefunc("cpython.array buffer")
def _(int L):
cdef int i
cdef array[double] arr = clone(array('d'), L, False)
cdef double d
for i in range(loops):
for i in range(L):
d = arr[i]
# Prevents dead-code elimination
str(d)
@timefunc("cpython.array memoryview")
def _(int L):
cdef int i
cdef double[::1] arr = clone(array('d'), L, False)
cdef double d
for i in range(loops):
for i in range(L):
d = arr[i]
# Prevents dead-code elimination
str(d)
@timefunc("cpython.array raw C type")
def _(int L):
cdef int i
cdef array arr = clone(array('d'), L, False)
cdef double d
for i in range(loops):
for i in range(L):
d = arr[i]
# Prevents dead-code elimination
str(d)
@timefunc("numpy.empty_like memoryview")
def _(int L):
cdef int i
cdef double[::1] arr = numpy.empty((L,), dtype='double')
cdef double d
for i in range(loops):
for i in range(L):
d = arr[i]
# Prevents dead-code elimination
str(d)
@timefunc("malloc")
def _(int L):
cdef int i
cdef double* arrptr = <double*> malloc(sizeof(double) * L)
cdef double d
for i in range(loops):
for i in range(L):
d = arrptr[i]
free(arrptr)
# Prevents dead-code elimination
str(d)
@timefunc("malloc memoryview")
def _(int L):
cdef int i
cdef double* arrptr = <double*> malloc(sizeof(double) * L)
cdef double[::1] arr = <double[:L]>arrptr
cdef double d
for i in range(loops):
for i in range(L):
d = arr[i]
free(arrptr)
# Prevents dead-code elimination
str(d)
@timefunc("cvarray memoryview")
def _(int L):
cdef int i
cdef double[::1] arr = cvarray((L,),sizeof(double),'d')
cdef double d
for i in range(loops):
for i in range(L):
d = arr[i]
# Prevents dead-code elimination
str(d)
出力します。
INITIALISATIONS
Running cpython.array buffer
0.100040 0.097140 0.133110 0.121820 0.131630 0.108420 0.112160 μs
Running cpython.array memoryview
0.339480 0.333240 0.378790 0.445720 0.449800 0.414280 0.414060 μs
Running cpython.array raw C type
0.048270 0.049250 0.069770 0.074140 0.076300 0.060980 0.060270 μs
Running numpy.empty_like memoryview
1.006200 1.012160 1.128540 1.212350 1.250270 1.235710 1.241050 μs
Running malloc
0.021850 0.022430 0.037240 0.046260 0.039570 0.043690 0.030720 μs
Running malloc memoryview
1.640200 1.648000 1.681310 1.769610 1.755540 1.804950 1.758150 μs
Running cvarray memoryview
1.332330 1.353910 1.358160 1.481150 1.517690 1.485600 1.490790 μs
ITERATING
Running cpython.array buffer
0.010000 0.027000 0.091000 0.669000 6.314000 64.389000 635.171000 μs
Running cpython.array memoryview
0.013000 0.015000 0.058000 0.354000 3.186000 33.062000 338.300000 μs
Running cpython.array raw C type
0.014000 0.146000 0.979000 9.501000 94.160000 916.073000 9287.079000 μs
Running numpy.empty_like memoryview
0.042000 0.020000 0.057000 0.352000 3.193000 34.474000 333.089000 μs
Running malloc
0.002000 0.004000 0.064000 0.367000 3.599000 32.712000 323.858000 μs
Running malloc memoryview
0.019000 0.032000 0.070000 0.356000 3.194000 32.100000 327.929000 μs
Running cvarray memoryview
0.014000 0.026000 0.063000 0.351000 3.209000 32.013000 327.890000 μs
(quot;iterations"ベンチマークの理由は、いくつかのメソッドはこの点で驚くほど異なる特性を持っているからです)。
初期化速度が速い順に
malloc
: これは厳しい世界ですが、速いです。多くのものをアロケートし、妨げのない反復処理とインデックス作成のパフォーマンスが必要なら、これでなければならない。でも、ふつうは......。
cpython.array raw C type
: いやあ、速いですねえ。そして安全だ。残念ながら、データフィールドにアクセスするためにPythonを経由しています。素晴らしいトリックを使えば、それを避けることができる。
arr.data.as_doubles[i]
というように、安全性を排除しつつ、標準的な速度に近づけています! これによって、これは
素晴らしい
の代わりになります。
malloc
は、基本的にかなり参照カウントされるバージョンです!
cpython.array buffer
: の3倍から4倍のセットアップ時間です。
malloc
のわずか3〜4倍のセットアップ時間で、これは素晴らしい賭けのように見えます。しかし残念ながら、これはかなりのオーバーヘッドがあります (ただし
boundscheck
と
wraparound
ディレクティブ)。つまり、フルセーフティ・バリアントとしか競合しませんが
は
であり、初期化が最も速いです。お好みでどうぞ。
cpython.array memoryview
: と比べて一桁遅くなりました。
malloc
よりも一桁遅くなりました。それは残念なことですが、同じように速く反復されます。これは、私が提案する標準的な解決策であり、もし
boundscheck
または
wraparound
がオンになっている場合(この場合
cpython.array buffer
はより説得力のあるトレードオフかもしれません)。
残りは 唯一価値があるのは
numpy
のもので、オブジェクトに付属する多くの楽しいメソッドのためです。それだけなんですけどね。
関連
-
[解決済み] JVM起動時のパラメータ「-Xms」「-Xmx」とは何ですか?
-
[解決済み] for'ループでインデックスにアクセスする?
-
[解決済み] Pythonのリストメソッドであるappendとextendの違いは何ですか?
-
[解決済み] __init__.py は何のためにあるのですか?
-
[解決済み] パラメータに**(ダブルスター/アスタリスク)、*(スター/アスタリスク)がありますが、これはどういう意味ですか?
-
[解決済み] Pythonで型をチェックする標準的な方法は何ですか?
-
[解決済み】__str__と__repr__の違いは何ですか?
-
[解決済み] 2つの線分が交差しているかどうかを確認するにはどうすればよいですか?
-
[解決済み] pandasのタイムゾーンに対応したDateTimeIndexを、特定のタイムゾーンに対応したナイーブなタイムスタンプに変換する。
-
[解決済み] Pythonで、ウェブサイトが404か200かを確認するためにurllibをどのように使用しますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 2つの線分が交差しているかどうかを確認するにはどうすればよいですか?
-
[解決済み] Jupyterノートブックでenv変数を設定する方法
-
[解決済み] PythonでSVGからPNGに変換する
-
[解決済み] 値で列挙名を取得する [重複]。
-
[解決済み] スペースがないテキストを単語のリストに分割する方法
-
[解決済み] オブジェクトのリストに特定の属性値を持つオブジェクトが含まれているかどうかをチェックする
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] Django で全てのリクエストヘッダを取得するにはどうすれば良いですか?
-
[解決済み] Flask でグローバル変数はスレッドセーフか?リクエスト間でデータを共有するには?
-
[解決済み] Pythonでリストが空かどうかをチェックする方法は?重複