53
Python и его тормоза Можно ли заставить питон работать быстро Александр Шигин, [email protected] Rambler, 2010

Python и его тормоза

Embed Size (px)

DESCRIPTION

Доклад на pycamp kiev.

Citation preview

Page 1: Python и его тормоза

Python и его тормозаМожно ли заставить питон работать быстро

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

Rambler, 2010

Page 2: Python и его тормоза

О чем я буду говорить

краткий рассказ о времени;простые примеры;быстрые простые примеры;глупые примеры;и еще глупости.

Page 3: Python и его тормоза

Время

Первый пример — real time.

$ time sleep 5

real 0m5.006suser 0m0.004ssys 0m0.008s

Page 4: Python и его тормоза

Время

Второй пример — user time.

$ time openssl rand \> -out /dev/null 9000000

real 0m0.421suser 0m0.388ssys 0m0.004s

Page 5: Python и его тормоза

Время

Третий пример — system time.

$ time LANG=C dd if=/dev/zero \> of=/dev/null count=900000 bs=1900000+0 records in900000+0 records out900000 bytes (900 kB) copied, 0.413783 s, 2.2 MB/s

real 0m0.417suser 0m0.096ssys 0m0.312s

Page 6: Python и его тормоза

Время

Для процесса есть три времени:real, CPU, system.

обычно нас интересует real time;но если мы запускаем многопараллельных задач мы можемупереться в CPU (user) time;системное время в основномзависит от количествасистемных вызовов.

Page 7: Python и его тормоза

Чуть-чуть чисел

вызов функции по указателю (нс)C Python bi Python pure4 140 270 [2.5]

130 260 [2.6]сумма массива из 400 целых чисел

C Python bi Python pure590 16 550 49 300 [2.5]

5 700 45 150 [2.6]

Page 8: Python и его тормоза

Чуть-чуть числа про объекты

создание чистого python объекта210 нс;создание python объекта спустым __slots__ 120 нс;создание embedded pythonобъекта 150 нс.

Page 9: Python и его тормоза

Создание объектов

создание кортежа из двухэлементов 31 нс;создание класса с двумя полями690 нс;распаковка кортежа 130 нс;доступ к полю кортежа 105 нс;доступ к полю объекта 110 нс.

Page 10: Python и его тормоза

Маленький пример

Как лучше хранить неизменяемыепары чисел? Учебный пример —нахождение центра масс.

кортеж из трех чисел: x, y,масса;класс с тремя полями;словарь.

Page 11: Python и его тормоза

Маленький пример: класс

class Po s i t i o n :def __init__( s e l f , x , y , mass ) :

s e l f . x = xs e l f . y = ys e l f . mass = mass

x = [ P o s i t i o n (0 , 0 , 10) ,P o s i t i o n (1 , 1 , 13) ,P o s i t i o n (1 , 2 , 5 ) ]

Page 12: Python и его тормоза

Маленький пример: класс

def get_cente r ( l s t ) :rx , ry , mass = 0 . 0 , 0 . 0 , 0 . 0for i t em in l s t :

r x += item . x ∗ i t em . massr y += item . y ∗ i t em . massmass += item . mass

return Po s i t i o n ( r x /mass , r y /mass ,mass )

Результат: 3900 нс

Page 13: Python и его тормоза

Маленький пример: объекты

новый класс ≈ 4100 нс;в 2.5 новый класс ≈ 4750 нс.__slots__ 2.6 ≈ 4050 нс, 2.5 —4500 нс.

Page 14: Python и его тормоза

Маленький пример: кортеж

def get_cente r ( l s t ) :rx , ry , rm = 0 . 0 , 0 . 0 , 0 . 0for x , y , mass in l s t :

r x += x ∗ massr y += y ∗ massrm += mass

return ( r x /rm , r y /rm , rm)

Результат: 2200 нс

Page 15: Python и его тормоза

Маленький пример: словарь

def get_cente r ( l s t ) :rx , ry , rm = 0 . 0 , 0 . 0 , 0 . 0for i t em in l s t :

r x += item [ ’ x ’ ] ∗ i t em [ ’ mass ’ ]r y += item [ ’ y ’ ] ∗ i t em [ ’ mass ’ ]rm += item [ ’ mass ’ ]

return ( r x /rm , r y /rm , rm)

Результат: 2600 нс

Page 16: Python и его тормоза

Маленький пример

Итог: используйте кортежи.

Меряем 2.5 2.6старый класс 4050 3900новый класс 4750 4130со слотами 4490 4050

кортежи 2250 2210словарь 2700 2630

Page 17: Python и его тормоза

Глупый пример

Смешные числа Фибоначи. Каклучше хранить текущую паручисел?

В этом примере мы будем изменятьпару.

Page 18: Python и его тормоза

Глупый пример: класс

Первый вариант.

class F :def __init__( s e l f , x , y ) :

s e l f . x = xs e l f . y = y

Page 19: Python и его тормоза

Глупый пример: класс

Проверяем:

x = F(1 , 1)t = x . yx . y = x . x + x . yx . x = t# так 4 разаРезультат: 2830 нс

Page 20: Python и его тормоза

Глупый пример: классы

x.x, x.y = x.y, x.x + x.yнемного медленнее;надо повторяться про новыеклассы?

Page 21: Python и его тормоза

Глупый пример: кортеж

Проверяем:

x = 1 , 1x = x [ 1 ] , x [ 0 ] + x [ 1 ]# так 4 разаРезультат: 1410 нс

Page 22: Python и его тормоза

Глупый пример: словарь

Проверяем:

x = d i c t ( x=1, y=1)t = x [ ’ y ’ ]x [ ’ y ’ ] = x [ ’ x ’ ] + x [ ’ y ’ ]x [ ’ x ’ ] = t# так 4 разаРезультат: 2500 нс

Page 23: Python и его тормоза

Глупый пример

Итог: даже в этом случаеиспользуйте кортежи.

Меряем 2.5 2.6старый класс 2910 2835новый класс 4630 3468со слотами 4065 3212

кортежи 1550 1410словарь 2810 2550

Page 24: Python и его тормоза

Замыкания

вызов замыкания 145 нс;возврат значения из замыкания166 нс;создание замыкания 380 нс;

Page 25: Python и его тормоза

Первый пример

Создадим класс, экземплярыкоторого будут возвращать свойаргумент, увеличенный на некоечисло, которое мы передадим присоздании класса.

x = X(14)x (15) # −> 29

Page 26: Python и его тормоза

Первый пример — старые классы

class X:def __init__( s e l f , x ) :

s e l f . x = xdef __call__( s e l f , x ) :

return s e l f . x + xx = X( 1 ) ; s = 0

# проверяемs += x (12)

Результат: 650 нс

Page 27: Python и его тормоза

Первый пример — новый класс

class X( ob j e c t ) :def __init__( s e l f , x ) :

s e l f . x = xdef __call__( s e l f , x ) :

return s e l f . x + xx = X( 1 ) ; s = 0

# проверяемs += x (12)

Результат: 650 → 404 нс

Page 28: Python и его тормоза

"Старые" классы

typedef struct {PyObject_HEADPyObject ∗ c l_base s ;PyObject ∗ c l_d i c t ;PyObject ∗cl_name ;

PyObject ∗ c l_get / s e t / d e l a t t r ;} PyC la s sOb j ec t ;

Page 29: Python и его тормоза

"Новые" классы

typedef struct _typeob j ec t {PyObject_VAR_HEAD

/∗ s k i p f i e l d s ∗/hash func tp_hash ;t e r n a r y f u n c t p_ca l l ;

/∗ s k i p f i e l d s ∗/} PyTypeObject ;

Page 30: Python и его тормоза

Первый пример — странный результат

class X:def __init__( s e l f , x ) :

s e l f . x = xdef c a l l ( s e l f , x ) :

return s e l f . x + xx = X( 1 ) ; s = 0

# проверяемs += x . c a l l (12)

Результат: 650 → 404 → 380 нс

Page 31: Python и его тормоза

Первый пример — замыкание

def X( x ) :def i n n e r ( y ) :

return x+yreturn i n n e r

x = X( 1 ) ; s = 0

# проверяемs += x (12)

Результат: 650 → 404 → 380 → 228 нс

Page 32: Python и его тормоза

Итераторы/генераторы

просчитать генератором до100 — 31 700 нс;просчитать итератором до100 — 82 200 нс;itertools.count — 7 400 нс;xrange(999) — 7 500 нс.

Проверка через list(islice(iterable, 100)).

Page 33: Python и его тормоза

Чуть-чуть реальный пример

Выделить тройки (uid, login,домашняя директория) из/etc/passwd.

Это достаточно часть первого этапаобработки больших файлов.

Page 34: Python и его тормоза

passwd: генератор

def f unc ( i a b l e ) :for l i n e in i a b l e :

x = l i n e . s p l i t ( ’ : ’ )y i e l d i n t ( x [ 2 ] ) , x [ 0 ] , x [ 5 ]

Page 35: Python и его тормоза

passwd: итератор

class f unc :def __init__( s e l f , i a b l e ) :

s e l f . i a b l e = i a b l e

def __iter__( s e l f ) : return s e l f

def next ( s e l f ) :l i n e = s e l f . i a b l e . nex t ( )x = l i n e . s p l i t ( ’ : ’ )return i n t ( x [ 2 ] ) , x [ 0 ] , x [ 5 ]

Page 36: Python и его тормоза

passwd: imap

def f unc ( l i n e ) :x = l i n e . s p l i t ( ’ : ’ )return i n t ( x [ 2 ] ) , x [ 0 ] , x [ 5 ]

Page 37: Python и его тормоза

passwd

Вывод: генераторы — это не толькоудобно, но и быстро.

2.5 2.6генератор 125 626 148 311итератор 181 100 210 167

imap 146 084 167 703

Page 38: Python и его тормоза

Некоторые общие вещи

Некоторые способы ускоритьвстроенный код:

interning;proxy-object;object cache.

Page 39: Python и его тормоза

string interning

Создание объекта требуетдополнительных действий.Если мы используем одну и туже строку постоянно, гораздобыстрее создать один раз pythonстроку, а потом передавать ее вpython API.Эта техника подходит не толькодля строк.

Page 40: Python и его тормоза

string interning: пример

while ( ( i tem = PyIter_Next ( i t e r a t o r ) )!= NULL) {

PyObject ∗ f i e l d = \PyObjec t_GetAt t rSt r i ng (item , " th " ) ;

// PyObject ∗ f i e l d = \// PyObject_GetAttr (// item , i n t e rned_th ) ;. . .Py_DECREF( i tem ) ;

}

Page 41: Python и его тормоза

string interning: итог

В вырожденных случаях C кодбудет медленнее чем Python код.

python код 14 830C-код, C строка 16 636

С-код, встроенная строка 8 862

Page 42: Python и его тормоза

proxy object

Если у вас есть развесистаяструктура «нативных»объектов, не надо для них всехсоздавать python объекты.Создание объектов потребованию экономит не тольковремя создания родительскогообъекта, но и память.

Page 43: Python и его тормоза

object cache

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

Page 44: Python и его тормоза

object cache

создание 50 тысяч int(5) — 450мкс (9 нс);создание 50 тысяч int(5000) —760 мкс (15 нс);кеш объектов в данном случаедал прирост в 40%.

Page 45: Python и его тормоза

Global Interpretor Lock

Все видели картинку про два CPUbound треда?

Картинка нагло украдена из статьи The Python GILVisualized http://www.dabeaz.com/

Page 46: Python и его тормоза

Global Interpretor Lock

Во время работы встроенныхфункций можно разблокироватьGIL, если мы не используемPython API.Хорошие примеры: py-lxml.

Page 47: Python и его тормоза

Python API

Сложно.Запутанно.Считать ссылки самому:Py_DECREF, Py_INCREF

Брррр...

Page 48: Python и его тормоза

Ужас

wh i l e ( ( i tem = PyIter_Next ( i t e r a t o r ) ) \!= NULL) {

PyObject ∗ f i e l d = PyObject_GetAttr (item , i n t e rned_th ) ;

i f ( f i e l d == NULL) {Py_DECREF( r e s u l t ) ;Py_DECREF( i tem ) ;r e t u r n NULL ;

}PyObject ∗nw = PyNumber_Add(

r e s u l t , f i e l d ) ;Py_DECREF( r e s u l t ) ;. . .

Page 49: Python и его тормоза

Ужас

de f sum_th ( l s t ) :r e s u l t = 0f o r i i n l s t : #!

r e s u l t += i . th #!! !111r e t u r n r e s u l t

Это гораздо проще!

Page 50: Python и его тормоза

Cython

Откомпилировав пример в Cython,я получил следующие результаты:

Python код 14 830C-код, C строка 16 636

С-код, встроенная строка 8 862Cython код 7 067

Page 51: Python и его тормоза

Выводы

догнать Python’ом C неполучиться;можно потерять 20% просто так;активно используя Cythonможно неплохо ускоритьпрограмму;и мало потерять ввыразительности.

Page 52: Python и его тормоза

Спасибо завнимание.

Page 53: Python и его тормоза

Вопросы?