उत्तर के लिए here देखें।
मूल विचार है कि आप चाहते हैं 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)
संपादित
ऐसा लगता है कि उस सूत्र में बेंचमार्क बकवास थे। यहाँ मेरी सेट है, मेरे समय के साथ:
# 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
(। "पुनरावृत्तियों" बेंचमार्क के लिए कारण यह है कि कुछ तरीकों को इस संबंध में आश्चर्यजनक रूप से अलग विशेषताएं हैं है)
प्रारंभिक गति के क्रम में:
malloc
: यह एक कठोर दुनिया है, लेकिन यह तेज़ है।यदि आपको बहुत सी चीजों को आवंटित करने की आवश्यकता है और इसे बिना किसी अनुक्रमित और अनुक्रमित प्रदर्शन की आवश्यकता है, तो यह होना चाहिए। लेकिन आम तौर पर आप के लिए एक अच्छी शर्त है ...
cpython.array raw C type
: ठीक है, यह तेज़ है। और यह सुरक्षित है। दुर्भाग्यवश यह अपने डेटा फ़ील्ड तक पहुंचने के लिए पायथन के माध्यम से जाता है। आप एक अद्भुत चाल का उपयोग कर इससे बच सकते हैं:
arr.data.as_doubles[i]
जो सुरक्षा को हटाने के दौरान इसे मानक गति तक लाता है! यह अद्भुतmalloc
के लिए प्रतिस्थापन बनाता है, मूल रूप से एक सुंदर संदर्भ-गणना संस्करण है!
cpython.array buffer
: malloc
के सेटअप समय में केवल तीन से चार गुना में आ रहा है, यह एक अद्भुत शर्त दिखता है। दुर्भाग्यवश इसमें महत्वपूर्ण ओवरहेड है (हालांकि boundscheck
और wraparound
निर्देशों की तुलना में कम है)। इसका मतलब है कि यह केवल पूर्ण सुरक्षा प्रकारों के खिलाफ वास्तव में प्रतिस्पर्धा करता है, लेकिन प्रारंभ करने वालों में से सबसे तेज़ है। आपकी पंसद।
cpython.array memoryview
: यह अब प्रारंभ करने के लिए malloc
से धीमी गति का क्रम है। यह एक शर्म की बात है, लेकिन यह तेजी से तेज़ करता है। यह मानक समाधान है जो मैं सुझाव दूंगा कि boundscheck
या wraparound
चालू हैं (जिस स्थिति में cpython.array buffer
अधिक आकर्षक व्यापार हो सकता है)।
बाकी। ऑब्जेक्ट्स से जुड़ी कई मजेदार विधियों के कारण, कुछ भी मूल्यवान numpy
है। हालांकि, यह है।
उत्कृष्ट सवाल, मुझे कुछ इसी तरह के बारे में आश्चर्य है। – AlexE
आपका बेंचमार्क सबसे अच्छा जवाब है जिसे मैं जानता हूं। फॉलो अप प्रश्न का उत्तर देने के लिए, आप बस अपनी NumPy सरणी को सामान्य तरीके से घोषित कर सकते हैं (आपको पुराने प्रकार के इंटरफ़ेस का उपयोग भी नहीं करना पड़ता है) और फिर कुछ प्राप्त करने के लिए 'cdef int [:] arrview = arr' जैसे कुछ करें NumPy सरणी के लिए उपयोग की जाने वाली एक ही स्मृति का दृश्य। आप तेजी से अनुक्रमण के लिए दृश्य और साइथन कार्यों के बीच स्लाइस पास करने के लिए उपयोग कर सकते हैं जबकि अभी भी NumPy सरणी के माध्यम से NumPy कार्यों तक पहुंच है। जब आप पूरा कर लेंगे तो आप केवल NumPy सरणी वापस कर सकते हैं। – IanH
वहाँ एक [अच्छा संबंधित प्रश्न है ...] (http://stackoverflow.com/q/18410342/832621) जहां आप देख सकते हैं कि np.empty धीमा हो सकता है ... –