Как предотвратить __Pyx_MemoryView_Len (__ pyx_v_a) взаимодействие с Python в Cython - PullRequest
0 голосов
/ 10 декабря 2018

У меня есть простая функция Cython, которая получает длину представления памяти:

cdef int get_length(int[:] a):
    return len(a)

Я компилирую компиляцию кода с помощью директивы annotate=True, чтобы я мог увидеть, где у Cython есть Pythonвзаимодействие.

Полученный html содержит этот текст для строки return len(a):

  __pyx_t_1 = __Pyx_MemoryView_Len(__pyx_v_a); 
  __pyx_r = __pyx_t_1;
  goto __pyx_L0;

Такое взаимодействие с Python должно быть медленным.Есть ли способ предотвратить взаимодействие с Python?Я пытался a.shape[0], но это не помогло.

1 Ответ

0 голосов
/ 10 декабря 2018

Вы не должны беспокоиться об этом, __Pyx_MemoryView_Len так же быстро, как он получает, потому что он определен как:

typedef struct {
  struct {{memview_struct_name}} *memview;
  char *data;
  Py_ssize_t shape[{{max_dims}}];
  ...
} {{memviewslice_name}};

// used for "len(memviewslice)"
#define __Pyx_MemoryView_Len(m) (m.shape[0])

Цвет этой строки не желтыйно желтоватый - что в основном означает, что это приводит не к чистому C-коду, а к тому, что используется некоторая функциональность _Pyx_XXX, которая часто совсем не плоха для производительности.

Нет Python-взаимодействие - после прохождения C-препроцессора C-компилятор увидит, что вы написали:

return a.shape[0]

, что, кстати, приводит к белой линии.

Если вас также интересует размер многомерного memview, то этот SO-вопрос может стоить прочитать.


Annotate показывает определение функции в виде желтоголиния.Тем не менее, только стоимость, когда модуль загружен (и он оплачивается один раз, а не каждый раз при вызове функции), отвечает за «желтый» цвет.

Посмотрите на полученный C-код:

static int __pyx_f_9my_module_get_length(__Pyx_memviewslice __pyx_v_a) {
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_length", 0);

  /* "my_module.pyx":5
 * 
 * cdef int get_length(int[:] a):
 *     return a.shape[0]             # <<<<<<<<<<<<<<
 */
  __pyx_r = (__pyx_v_a.shape[0]);
  goto __pyx_L0;

  /* "my_module.pyx":4
 *     return 3. * a
 * 
 * cdef int get_length(int[:] a):             # <<<<<<<<<<<<<<
 *     return a.shape[0]
 */

  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

RefNannyXXXX активен только при сборке с CYTHON_REFNANNY -определенным.

Существует также другой код, показанный annotate -инструментом, которыйсоответствует cdef int get_length(int[:] a)::

/* … */
  __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

Однако этот код является частью __pyx_pymod_exec_XXXXX / PyInit_XXXXX и вызывается только один раз, когда загружается модуль.На самом деле, я не уверен, как это связано с get_length и зачем это нужно, но поскольку затраты настолько малы, я никогда не заботился о том, чтобы выяснить это.

...