python и cython

53
Python и Cython Оптимизация и стыковка с C Александр Шигин, [email protected] Rambler, 2010

Upload: alexander-shigin

Post on 28-May-2015

2.636 views

Category:

Technology


4 download

DESCRIPTION

Удобное ускорения Python'а с помощью Cython. Доклад для devconf-2010.

TRANSCRIPT

Python и CythonОптимизация и стыковка с C

Александр Шигин, [email protected], 2010

Python — удобно

... но не быстро

Python — удобно... но не быстро

• динамический язык;• байт код без компиляции;• GC на счетчике ссылок;• Global Interpretor Lock;• если что-то работает медленнееpython’а, это не значит чтоpython быстрый.

• динамический язык;• байт код без компиляции;• GC на счетчике ссылок;• Global Interpretor Lock;• если что-то работает медленнееpython’а, это не значит чтоpython быстрый.

Еще про ref-counting

• процессы — плохая заменатредам;

• не работает Copy–on–Write;• мы не можем легкораспараллелить программу,когда у нас много данных.

...d = d i c t ( ( i , ’ the ␣ s t r i n g ␣wi th ␣%d ’ % i )

for i in x range (500∗1000))t ime . s l e e p (10)s y s . s t d e r r . w r i t e ( ’ about ␣ to ␣ f o r k . . . \ n ’ )os . f o r k ( )

for i , k in d . i t e r i t e m s ( ) :pass

t ime . s l e e p (10)

C — не так удобно

... но достаточнобыстро

C — не так удобно... но достаточно

быстро

C + Python = ???

медленнее Cа удобно?

C + Python =

???

медленнее C

а удобно?

C + Python =

???

медленнее Cа удобно?

Pythondef sum_th(lst):

result = 0for i in lst: #!

result += i.th #!!!111return result

Pure Clong sum_th(const struct with_th_t *all,

size_t size) {long result = 0;size_t i;for (i = 0; i < size; ++i) {

result += all[i].th;}return result;

}

Модуль на Cwhile ((item = PyIter_Next(iterator)) != NULL) {

PyObject *field = PyObject_GetAttr(item, interned_th);

if (field == NULL) {Py_DECREF(result);Py_DECREF(item);return NULL;

}PyObject *nw = PyNumber_Add( result, field);Py_DECREF(result);...

Python

def sum_th(lst):result = 0for i in lst: #!

result += i.th #!!!111return result

Осторожно,benchmark!

Итого

Python Pure C C moduleстрок 5 7 28

• На реальном коде разница будетменьше!

• Но разница будет.

???

Долго писать:• много кода;• сложность отладки.

Потеря скорости:• boxing/unboxing.

boxing/unboxing

PyInt_FromSize_t

PyInt_FromLong PyLong_FromSize_t

fill_free_list _PyLong_FromByteArray

_PyLong_New

boxing/unboxingPyInt_AsLong

PyInt_Check tp_as_number

PyInt_AS_LONG PyInt_Check

PyInt_AS_LONG PyLong_Check

PyLong_AsLong

Cython

• страшная смесь Python’а и C;• понимает подмножество Python;• генерирует C-код;• def/cdef/cpdef.• lxml, SciPy, ...

• читайте FAQ;• используйте cdef;• не *q = 0, а q[0] = 0;• не путайте float и double;• cdef для переменных, которыеучаствуют в циклах;

• cython -a.

shlex.split• Ускорим простую программув XX раз.

• За 15 минут.• Сейчас это займет куда меньшевремени.

Задача127.0.0.1 "it’s query" "client id" 12.0 ...

• str.split не сработает: некоторыеполя окружены кавычками.

• 25 миллионов строк в день.• 680 миллионов строк в месяц.

Что имеемsm = 0.0cnt = 0for line in sys.stdin:

split = shlex.split(line)try:

sm += float(split[12])cnt += 1

except ValueError:pass

Что имеемИспользуем стандартный shlex.split и файл в 900строк.

SUMMARYreal time: 0.870 [ 0.875 +-0.004] 0.878sys time: 0.004 [ 0.007 +-0.002] 0.008user time: 0.844 [ 0.860 +-0.014] 0.868

≈ 1 мс на строку.≈ 7 часов на дневной лог

Что имеем

Своя, очень простая реализация. Тот же файл.

SUMMARYreal time: 0.603 [ 0.614 +-0.009] 0.621sys time: 0.000 [ 0.001 +-0.002] 0.004user time: 0.596 [ 0.601 +-0.006] 0.608

≈ 0.7 мс на строку.≈ 5 часов на дневной лог

Что имеем

Та же реализация, но откомпилированная вcython. Тот же файл.

SUMMARYreal time: 0.650 [ 0.664 +-0.013] 0.675sys time: 0.000 [ 0.000 +-0.000] 0.000user time: 0.640 [ 0.655 +-0.014] 0.668

cython -a

Уберем Python API

Уберем Python API

Time table

время0.603 исходный код0.532 объявить типы0.151 cdef class0.029 char *

≈ 14 минут на дневной лог файл.

Cython vs ...

• boost::python;• SWIG;• expy;• ...

Проблема boxing/unboxing

1 Найдем функцию, что занимает>50% времени.

2 Перепишем её на C.3 ???

4 Нет профита.

Проблема boxing/unboxing

1 Найдем функцию, что занимает>50% времени.

2 Перепишем её на C.3 ???4 Нет профита.

Профилирование

Подход ускорения черезпрофилирование порочен:• не надо думать, что остальнаяпрограмма ускорится;

• что делать, если нет очевидногомедленного места?

Кроме этого

• на каждый вызов функции надопреобразовывать данные;

• в вырожденных случаях, этобудет дольше самой функции;

• мы вынуждены переписыватьвсе места, где мы вызываемнашу функцию.

Решение

• частичная оптимизация;• cpdef;• перетаскивание функционала вcython, а потом в C;

• это не панацея.

Сложные данные

Как работать с данными из C иPython.• proxy/wrapper;• копия.

Копирование vs proxy

proxy:• каждый раз преобразовывать;• но есть кеш объектов;• код на C работает быстро;• это тот код, который насинтересует.

Копирование vs proxy

Копирование:• идеально для неизменяемыхобъектов;

• но требует много памяти;• fork...

Еще раз про GIL

GIL — это непроблема

GIL

• он нужен, пока мы работаем сpython данными;

• в критичных местах, мы неработаем с python данными;

• мы можем его отпустить.

proxy: запрет создания изpython

cdef class _Q:def __cinit__(self, ....):

....

def __init__(self, ....):raise TypeError, ""

cpdef _Q Q(....):cdef _Q q = _Q.__new__(_Q)return q

Кеширование объектов

• попробуйте id;• попробуйте перенумеровать взависимости от частоты;

• убедитесь, что у васнеизменяемые типы;

• треды...

Кеширование проксиобъектов

Python container a[0] a[1] ... a[n]

C struct ... void *extra

container struct Python proxy

Кеширование проксиобъектов

Python container a[0] a[1] ... a[n]

C struct ... void *extra__getitem__

Python proxy container struct next Python proxy ...

Кеширование проксиобъектов

cdef _Point point_wrap(point_t *x):cdef _Point resultif x.extra != NULL:

return <_Point>x.extraresult = _Point.__new__(_Point)result.inner = xif is_common_point(x):

print ’cache’x.extra = <void *>result

return result

Мои выводы

• python — это удобно;• С — это быстро;• cython объединяет;• все будет хорошо.

Благодарю завнимание

[email protected]/shigin

Вопросы?

[email protected]/shigin