Cython: memory size attribute

I use a lot of 3D memory in Cython, for example.

cython.declare(a='double[:, :, ::1]')
a = np.empty((10, 20, 30), dtype='double')

I often want to go through all the elements a. I can do this using a triple loop like

for i in range(a.shape[0]):
    for j in range(a.shape[1]):
        for k in range(a.shape[2]):
            a[i, j, k] = ...

If I do not need indexes i, jand kit will be more efficient to execute a flat cycle, for example

cython.declare(a_ptr='double*')
a_ptr = cython.address(a[0, 0, 0])
for i in range(size):
    a_ptr[i] = ...

(size) . shape, .. size = a.shape[0]*a.shape[1]*a.shape[2], , , size = np.prod(np.asarray(a).shape). , , ( ) . - size , size = a.size. , , C, html , Cython. , C, size = a.shape[0]*a.shape[1]*a.shape[2],

__pyx_v_size = (((__pyx_v_a.shape[0]) * (__pyx_v_a.shape[1])) * (__pyx_v_a.shape[2]));

C-, size = a.size,

__pyx_t_10 = __pyx_memoryview_fromslice(__pyx_v_a, 3, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 2238, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_10);
__pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_size); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 2238, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_14);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_t_14); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 2238, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
__pyx_v_size = __pyx_t_7;

, , , C-, a.size . , size " , . , , shape. docs.

, , a.shape[0]*a.shape[1]*a.shape[2], ?

+4
2

C-, , size , C-. Cython- :

@cname('__pyx_memoryview')
cdef class memoryview(object):
...
   cdef object _size
...
    @property
    def size(self):
        if self._size is None:
            result = 1

            for length in self.view.shape[:self.view.ndim]:
                result *= length

            self._size = result

return self._size

, , . , 3- , ( , 8 , , ).

size - size /, . , , size - cython.

a.size - cython python.

, @danny python-call, . , :

%%cython
...
def both():
    a.size+a.shape[0]*a.shape[1]*a.shape[2]

,

>>> %timeit mv_size
22.5 ns ± 0.0864 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

>>> %timeit mv_product
20.7 ns ± 0.087 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

>>>%timeit both
21 ns ± 0.39 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

. :

%%cython
...
def nothing():
   pass

:

%timeit nothing
24.3 ns ± 0.854 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

: a.size - , , , , - .


: a __Pyx_memviewslice, __pyx_memoryview, . __Pyx_memviewslice :

struct __pyx_memoryview_obj;
typedef struct {
  struct __pyx_memoryview_obj *memview;
  char *data;
  Py_ssize_t shape[8];
  Py_ssize_t strides[8];
  Py_ssize_t suboffsets[8];
} __Pyx_memviewslice;

, shape Cython-, C- (, , , 8 ?). : 8 ).

memview - , __pyx_memoryview_obj - C-, cython, , :

/* "View.MemoryView":328
 * 
 * @cname('__pyx_memoryview')
 * cdef class memoryview(object):             # <<<<<<<<<<<<<<
 * 
 *     cdef object obj
 */
struct __pyx_memoryview_obj {
  PyObject_HEAD
  struct __pyx_vtabstruct_memoryview *__pyx_vtab;
  PyObject *obj;
  PyObject *_size;
  PyObject *_array_interface;
  PyThread_type_lock lock;
  __pyx_atomic_int acquisition_count[2];
  __pyx_atomic_int *acquisition_count_aligned_p;
  Py_buffer view;
  int flags;
  int dtype_is_object;
  __Pyx_TypeInfo *typeinfo;
};

, Pyx_memviewslice Python - , , shape stride, .

, a.size? __pyx_memoryview_fromslice, memview __Pyx_memviewslice -.

size , _size, Cython.

, - , shape, strides suboffsets, size, , , , - C- shape.

+2

C a.size .

Python, python. size python ssize_t. C. , size Py_ssize_t, ssize_t.

C , - python, .

- .

:

cimport numpy as np
import numpy as np
cimport cython
cython.declare(a='double[:, :, ::1]')
a = np.empty((10, 20, 30), dtype='double')

def mv_size():
    return a.size
def mv_product():
    return a.shape[0]*a.shape[1]*a.shape[2]

:

%timeit mv_size
10000000 loops, best of 3: 23.4 ns per loop

%timeit mv_product
10000000 loops, best of 3: 23.4 ns per loop

.

- C, , , size.

+1

Source: https://habr.com/ru/post/1696309/


All Articles