2014-01-07 3 views
8

Рассмотрима этого фиктивного код Cython:Cython Memoryview в качестве возвращаемого значения

#!python 
#cython: boundscheck=False 
#cython: wraparound=False 
#cython: initializedcheck=False 
#cython: cdivision=True 
#cython: nonecheck=False 

import numpy as np 

# iterator function 
cdef double[:] f(double[:] data): 
    data[0] *= 1.01 
    data[1] *= 1.02 
    return data 

# looping function 
cdef double[:] _call_me(int bignumber, double[:] data): 
    cdef int ii 
    for ii in range(bignumber): 
     data = f(data) 
    return data 

# helper function to allow calls from Python 
def call_me(bignumber): 
    cdef double[:] data = np.ones(2) 
    return _call_me(bignumber, data) 

Теперь, если я делаю Cython -a на это, он показывает заявление возврата в желтом цвете. Я делаю что-то подобное в очень критичной для производительности программе, и, согласно профилированию, это действительно замедляет мой код. Итак, зачем cython нужен python для этих операторов возврата? Аннотированный файл дает подсказку:

PyErr_SetString(PyExc_TypeError,"Memoryview return value is not initialized"); 

Удивительно, но поиск Google для Cython «возвращаемое значение Memoryview не инициализирован» дает нулевой результат.

+0

Cython version 0.19.2 – HenriV

+0

В вашем реальном коде вам нужно вернуть memoryview или изменить его на месте, как здесь? Выполнение этих изменений дает мне 40-кратное ускорение. Я не уверен, есть ли способ отключить эту проверку ... – jorgeca

+0

Настоящий код итерационно решает обычные дифференциальные уравнения, так что да, мне нужно вернуть его. – HenriV

ответ

3

Медленная часть - это не то, что вы думаете. Медленная часть (ну ... в первую очередь)

data = f(data) 

Не f(data). data =.

Это присваивает struct, который определяется как так

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; 

и назначение упомянуто делает

__pyx_t_3 = __pyx_f_3cyt_f(__pyx_v_data); 

, где находится __pyx_t_3 этого типа. Если это сделано в цикле, как есть, для копирования структур требуется гораздо больше времени, чем для выполнения тривиального тела функции. Я сделал время в чистом C, и он дает аналогичные номера.

(Изменить примечание: Присвоение на самом деле в первую очередь является проблемой, поскольку она также вызывает поколение из структур и других копий не оптимизированными.)

Однако, все это кажется глупым. Единственная причина для копирования структуры - это если что-то изменилось, но ничего не произошло. Точки памяти в одном и том же месте, точки данных в одном и том же месте и форма, шаги и смещения одинаковы.

Единственный способ избежать копирования struct - не изменять ни одно из его ссылок (ака. Всегда возвращать memoryview). Это возможно только в тех случаях, когда возвращение в любом случае бессмысленно, как здесь. Или вы можете взломать C, я думаю, как и я. Просто не плачь, если что-то сломаешь.


Также обратите внимание, что вы можете сделать свою функцию nogil, поэтому она не может иметь ничего общего с возвращаясь к Python.


EDIT

оптимизирующий компилятор C был бросать меня немного прочь. В принципе, я удалил некоторые присваивания и удалил множество других вещей. В основном медленный путь таков:

#include<stdio.h> 


struct __pyx_memoryview_obj; 


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


static __Pyx_memviewslice __pyx_f_3cyt_f(__Pyx_memviewslice __pyx_v_data) { 
    __Pyx_memviewslice __pyx_r = { 0, 0, { 0 }, { 0 }, { 0 } }; 
    __pyx_r = __pyx_v_data; 
    return __pyx_r; 
} 

main() { 
    int i; 
    __Pyx_memviewslice __pyx_v_data = {0, 0, { 0 }, { 0 }, { 0 }}; 

    for (i=0; i<10000000; i++) { 
     __pyx_v_data = __pyx_f_3cyt_f(__pyx_v_data); 
    } 
} 

(скомпилируйте без каких-либо оптимизаций).Я не программист на C, поэтому извиняюсь, если то, что я сделал, в какой-то степени не вписывается в то, что я скопировал компьютерный код.

Я знаю, что это не help, но я сделал все возможное, хорошо?

+2

+1 для того, чтобы показать, что это сложнее, чем я думал, и для ногила. – HenriV

Смежные вопросы