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


  Александр Шигин, shigin@rambler-co.ru


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


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

 Первый пример    real time.
 $ time sleep 5

 real    0m5.006s
 user    0m0.004s
 sys 0m0.008s
Время

 Второй пример   user time.
 $ time openssl rand 
 > -out /dev/null 9000000

 real    0m0.421s
 user    0m0.388s
 s...
Время
 Третий пример   system time.
 $ time LANG=C dd if=/dev/zero 
 > of=/dev/null count=900000 bs=1
 900000+0 records in...
Время
 Для процесса есть три времени:
 real, CPU, system.
     обычно нас интересует real time;
     но если мы запускаем ...
Чуть-чуть чисел

     вызов функции по указателю (нс)
           C Python bi Python pure
            4    140       270 [2...
Чуть-чуть числа про объекты


     создание чистого python объекта
     210 нс;
     создание python объекта с
     пустым...
Создание объектов

     создание кортежа из двух
     элементов 31 нс;
     создание класса с двумя полями
     690 нс;
  ...
Маленький пример

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


  class P o s i t i o n :
      def __init__ ( s e l f , x , y , mass ) :
           self .x = x...
Маленький пример: класс


  def g e t _ c e n t e r ( l s t ) :
      rx , ry , mass = 0 . 0 , 0 . 0 , 0 . 0
      for i t...
Маленький пример: объекты



    новый класс ≈ 4100 нс;
    в 2.5 новый класс ≈ 4750 нс.
    __slots__ 2.6 ≈ 4050 нс, 2.5
...
Маленький пример: кортеж


  def g e t _ c e n t e r ( l s t ) :
      rx , ry , rm = 0 . 0 , 0 . 0 , 0 . 0
      for x , ...
Маленький пример: словарь


  def g e t _ c e n t e r ( l s t ) :
      rx , ry , rm = 0 . 0 , 0 . 0 , 0 . 0
      for i t...
Маленький пример

 Итог: используйте кортежи.
           Меряем      2.5    2.6
      старый класс    4050   3900
       н...
Глупый пример


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

  В этом примере мы будем изменять
  ...
Глупый пример: класс


  Первый вариант.
  class F :
      def __init__ ( s e l f , x , y ) :
            self .x = x
    ...
Глупый пример: класс

 Проверяем:
 x = F ( 1 , 1)
 t = x.y
 x.y = x.x + x.y
 x.x = t
 # так 4 раза
 Результат: 2830 нс
Глупый пример: классы



     x.x, x.y = x.y, x.x + x.y
     немного медленнее;
     надо повторяться про новые
     класс...
Глупый пример: кортеж


 Проверяем:
 x = 1, 1
 x = x [1] , x [0] + x [1]
 # так 4 раза
 Результат: 1410 нс
Глупый пример: словарь

 Проверяем:
 x = d i c t ( x =1, y=1)
 t = x [ ’y ’ ]
 x[ ’y ’ ] = x[ ’x ’ ] + x[ ’y ’ ]
 x[ ’x ’ ...
Глупый пример
  Итог: даже в этом случае
  используйте кортежи.
            Меряем      2.5    2.6
       старый класс    ...
Замыкания



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

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

  class X:
      def __init__ ( s e l f , x ) :
           self .x = x
      def __...
Первый пример              новый класс

  c l a s s X( o b j e c t ) :
          def __init__ ( s e l f , x ) :
          ...
"Старые" классы


  typedef struct {
      PyObject_HEAD
      PyObject     ∗ cl_bases ;
      PyObject     ∗cl_dict ;
   ...
"Новые" классы


  typedef struct _ t y p e o b j e c t {
             PyObject_VAR_HEAD
  /∗ s k i p f i e l d s ∗/
     ...
Первый пример               странный результат

  class X:
      def __init__ ( s e l f , x ) :
           self .x = x
   ...
Первый пример            замыкание

  def X( x ) :
      def i n n e r ( y ) :
             return x+y
      return i n n ...
Итераторы/генераторы

      просчитать генератором до
      100 31 700 нс;
      просчитать итератором до
      100 82 200...
Чуть-чуть реальный пример


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

  Это достаточно част...
passwd: генератор



  def f u n c ( i a b l e ) :
      for l i n e in i a b l e :
              x = line . split ( ’ : ’...
passwd: итератор

  class func :
      def __init__ ( s e l f , i a b l e ) :
          self . iable = iable

       def _...
passwd: imap




  def f u n c ( l i n e ) :
      x = line . split ( ’ : ’)
      return i n t ( x [ 2 ] ) , x [ 0 ] , x ...
passwd

  Вывод: генераторы это не только
  удобно, но и быстро.
                     2.5     2.6
         генератор 125 6...
Некоторые общие вещи


  Некоторые способы ускорить
  встроенный код:
    interning;
    proxy-object;
    object cache.
string interning

      Создание объекта требует
      дополнительных действий.
      Если мы используем одну и ту
      ж...
string interning: пример

  while ( ( i t e m = P y I t e r _ N e x t ( i t e r a t o r ) )
            != NULL) {
      P...
string interning: итог

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

                   python код 14 ...
proxy object

     Если у вас есть развесистая
     структура нативных
     объектов, не надо для них всех
     создавать ...
object cache

     Если объекты неизменяемые и
     одни объекты встречаются чаще
     чем другие, можно возвращать
     з...
object cache


     создание 50 тысяч int(5) 450
     мкс (9 нс);
     создание 50 тысяч int(5000)
     760 мкс (15 нс);
 ...
Global Interpretor Lock

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




  Картинка нагло украдена из статьи The Pyth...
Global Interpretor Lock


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


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

  Брррр...
Ужас
 w h i l e (( item = PyIter_Next ( i t e r a t o r )) 
              != NULL) {
         PyObject ∗ f i e l d = PyObj...
Ужас


 d e f sum_th ( l s t ) :
       result = 0
       for i in l s t :             #!
           r e s u l t += i . t ...
Cython

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

    догнать Python’ом C не
    получиться;
    можно потерять 20% просто так;
    активно используя Cython
    мож...
Спасибо за
внимание.
Вопросы?
Upcoming SlideShare
Loading in …5
×

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

2,601 views

Published on

Доклад на pycamp kiev.

Published in: Technology
  • Be the first to comment

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

  1. 1. Python и его тормоза Можно ли заставить питон работать быстро Александр Шигин, shigin@rambler-co.ru Rambler, 2010
  2. 2. О чем я буду говорить краткий рассказ о времени; простые примеры; быстрые простые примеры; глупые примеры; и еще глупости.
  3. 3. Время Первый пример real time. $ time sleep 5 real 0m5.006s user 0m0.004s sys 0m0.008s
  4. 4. Время Второй пример user time. $ time openssl rand > -out /dev/null 9000000 real 0m0.421s user 0m0.388s sys 0m0.004s
  5. 5. Время Третий пример system time. $ time LANG=C dd if=/dev/zero > of=/dev/null count=900000 bs=1 900000+0 records in 900000+0 records out 900000 bytes (900 kB) copied, 0.413783 real 0m0.417s user 0m0.096s sys 0m0.312s
  6. 6. Время Для процесса есть три времени: real, CPU, system. обычно нас интересует real time; но если мы запускаем много параллельных задач мы можем упереться в CPU (user) time; системное время в основном зависит от количества системных вызовов.
  7. 7. Чуть-чуть чисел вызов функции по указателю (нс) C Python bi Python pure 4 140 270 [2.5] 130 260 [2.6] сумма массива из 400 целых чисел C Python bi Python pure 590 16 550 49 300 [2.5] 5 700 45 150 [2.6]
  8. 8. Чуть-чуть числа про объекты создание чистого python объекта 210 нс; создание python объекта с пустым __slots__ 120 нс; создание embedded python объекта 150 нс.
  9. 9. Создание объектов создание кортежа из двух элементов 31 нс; создание класса с двумя полями 690 нс; распаковка кортежа 130 нс; доступ к полю кортежа 105 нс; доступ к полю объекта 110 нс.
  10. 10. Маленький пример Как лучше хранить неизменяемые пары чисел? Учебный пример нахождение центра масс. кортеж из трех чисел: x, y, масса; класс с тремя полями; словарь.
  11. 11. Маленький пример: класс class P o s i t i o n : def __init__ ( s e l f , x , y , mass ) : self .x = x self .y = y s e l f . mass = mass x = [ P o s i ti o n (0 , 0 , 10) , P o si t i on (1 , 1 , 13) , Position (1 , 2 , 5)]
  12. 12. Маленький пример: класс def g e t _ c e n t e r ( l s t ) : rx , ry , mass = 0 . 0 , 0 . 0 , 0 . 0 for i t e m in l s t : r x += i t e m . x ∗ i t e m . mass r y += i t e m . y ∗ i t e m . mass mass += i t e m . mass return P o s i t i o n ( r x / mass , r y / mass , mass ) Результат: 3900 нс
  13. 13. Маленький пример: объекты новый класс ≈ 4100 нс; в 2.5 новый класс ≈ 4750 нс. __slots__ 2.6 ≈ 4050 нс, 2.5 4500 нс.
  14. 14. Маленький пример: кортеж def g e t _ c e n t e r ( l s t ) : rx , ry , rm = 0 . 0 , 0 . 0 , 0 . 0 for x , y , mass in l s t : r x += x ∗ mass r y += y ∗ mass rm += mass return ( r x /rm , r y /rm , rm ) Результат: 2200 нс
  15. 15. Маленький пример: словарь def g e t _ c e n t e r ( l s t ) : rx , ry , rm = 0 . 0 , 0 . 0 , 0 . 0 for i t e m in l s t : r x += i t e m [ ’ x ’ ] ∗ i t e m [ ’ mass ’ ] r y += i t e m [ ’ y ’ ] ∗ i t e m [ ’ mass ’ ] rm += i t e m [ ’ mass ’ ] return ( r x /rm , r y /rm , rm ) Результат: 2600 нс
  16. 16. Маленький пример Итог: используйте кортежи. Меряем 2.5 2.6 старый класс 4050 3900 новый класс 4750 4130 со слотами 4490 4050 кортежи 2250 2210 словарь 2700 2630
  17. 17. Глупый пример Смешные числа Фибоначи. Как лучше хранить текущую пару чисел? В этом примере мы будем изменять пару.
  18. 18. Глупый пример: класс Первый вариант. class F : def __init__ ( s e l f , x , y ) : self .x = x self .y = y
  19. 19. Глупый пример: класс Проверяем: x = F ( 1 , 1) t = x.y x.y = x.x + x.y x.x = t # так 4 раза Результат: 2830 нс
  20. 20. Глупый пример: классы x.x, x.y = x.y, x.x + x.y немного медленнее; надо повторяться про новые классы?
  21. 21. Глупый пример: кортеж Проверяем: x = 1, 1 x = x [1] , x [0] + x [1] # так 4 раза Результат: 1410 нс
  22. 22. Глупый пример: словарь Проверяем: x = d i c t ( x =1, y=1) t = x [ ’y ’ ] x[ ’y ’ ] = x[ ’x ’ ] + x[ ’y ’ ] x[ ’x ’ ] = t # так 4 раза Результат: 2500 нс
  23. 23. Глупый пример Итог: даже в этом случае используйте кортежи. Меряем 2.5 2.6 старый класс 2910 2835 новый класс 4630 3468 со слотами 4065 3212 кортежи 1550 1410 словарь 2810 2550
  24. 24. Замыкания вызов замыкания 145 нс; возврат значения из замыкания 166 нс; создание замыкания 380 нс;
  25. 25. Первый пример Создадим класс, экземпляры которого будут возвращать свой аргумент, увеличенный на некое число, которое мы передадим при создании класса. x = X( 1 4 ) x (15) # −> 29
  26. 26. Первый пример старые классы class X: def __init__ ( s e l f , x ) : self .x = x def __call__ ( s e l f , x ) : return s e l f . x + x x = X(1); s = 0 # проверяем s += x ( 1 2 ) Результат: 650 нс
  27. 27. Первый пример новый класс c l a s s X( o b j e c t ) : def __init__ ( s e l f , x ) : self .x = x def __call__ ( s e l f , x ) : return s e l f . x + x x = X(1); s = 0 # проверяем s += x ( 1 2 ) Результат: 650 → 404 нс
  28. 28. "Старые" классы typedef struct { PyObject_HEAD PyObject ∗ cl_bases ; PyObject ∗cl_dict ; PyObject ∗cl_name ; PyObject ∗ cl_get / set / d e l a t t r ; } PyClassObject ;
  29. 29. "Новые" классы typedef struct _ t y p e o b j e c t { PyObject_VAR_HEAD /∗ s k i p f i e l d s ∗/ h a s h f u n c tp_hash ; ternaryfunc tp_call ; /∗ s k i p f i e l d s ∗/ } PyTypeObject ;
  30. 30. Первый пример странный результат class X: def __init__ ( s e l f , x ) : self .x = x def c a l l ( s e l f , x ) : return s e l f . x + x x = X(1); s = 0 # проверяем s += x . c a l l ( 1 2 ) Результат: 650 → 404 → 380 нс
  31. 31. Первый пример замыкание def X( x ) : def i n n e r ( y ) : return x+y return i n n e r x = X(1); s = 0 # проверяем s += x ( 1 2 ) Результат: 650 → 404 → 380 → 228 нс
  32. 32. Итераторы/генераторы просчитать генератором до 100 31 700 нс; просчитать итератором до 100 82 200 нс; itertools.count 7 400 нс; xrange(999) 7 500 нс. Проверка через list(islice(iterable, 100)).
  33. 33. Чуть-чуть реальный пример Выделить тройки (uid, login, домашняя директория) из /etc/passwd. Это достаточно часть первого этапа обработки больших файлов.
  34. 34. passwd: генератор def f u n c ( i a b l e ) : for l i n e in i a b l e : x = line . split ( ’ : ’) yield int (x [2]) , x [0] , x [5]
  35. 35. passwd: итератор class func : def __init__ ( s e l f , i a b l e ) : self . iable = iable def __iter__ ( s e l f ) : return s e l f def n e x t ( s e l f ) : l i n e = s e l f . i a b l e . next () x = line . split ( ’ : ’) return i n t ( x [ 2 ] ) , x [ 0 ] , x [ 5 ]
  36. 36. passwd: imap def f u n c ( l i n e ) : x = line . split ( ’ : ’) return i n t ( x [ 2 ] ) , x [ 0 ] , x [ 5 ]
  37. 37. passwd Вывод: генераторы это не только удобно, но и быстро. 2.5 2.6 генератор 125 626 148 311 итератор 181 100 210 167 imap 146 084 167 703
  38. 38. Некоторые общие вещи Некоторые способы ускорить встроенный код: interning; proxy-object; object cache.
  39. 39. string interning Создание объекта требует дополнительных действий. Если мы используем одну и ту же строку постоянно, гораздо быстрее создать один раз python строку, а потом передавать ее в python API. Эта техника подходит не только для строк.
  40. 40. string interning: пример while ( ( i t e m = P y I t e r _ N e x t ( i t e r a t o r ) ) != NULL) { PyObject ∗ f i e l d = PyObject_GetAttrString ( item , " t h " ) ; // PyObject ∗ f i e l d = // PyObject_GetAttr ( // item , i n t e r n e d _ t h ) ; ... Py_DECREF( i t e m ) ; }
  41. 41. string interning: итог В вырожденных случаях C код будет медленнее чем Python код. python код 14 830 C-код, C строка 16 636 С-код, встроенная строка 8 862
  42. 42. proxy object Если у вас есть развесистая структура нативных объектов, не надо для них всех создавать python объекты. Создание объектов по требованию экономит не только время создания родительского объекта, но и память.
  43. 43. object cache Если объекты неизменяемые и одни объекты встречаются чаще чем другие, можно возвращать заранее созданные объекты. Хорошие примеры: целые числа, короткие строки, узел дерева без детей, единичные массивы.
  44. 44. object cache создание 50 тысяч int(5) 450 мкс (9 нс); создание 50 тысяч int(5000) 760 мкс (15 нс); кеш объектов в данном случае дал прирост в 40%.
  45. 45. Global Interpretor Lock Все видели картинку про два CPU bound треда? Картинка нагло украдена из статьи The Python GIL Visualized http://www.dabeaz.com/
  46. 46. Global Interpretor Lock Во время работы встроенных функций можно разблокировать GIL, если мы не используем Python API. Хорошие примеры: py-lxml.
  47. 47. Python API Сложно. Запутанно. Считать ссылки самому: Py_DECREF, Py_INCREF Брррр...
  48. 48. Ужас w h i l e (( item = PyIter_Next ( i t e r a t o r )) != NULL) { PyObject ∗ f i e l d = PyObject_GetAttr ( item , i n t e r n e d _ t h ) ; i f ( f i e l d == NULL) { Py_DECREF( r e s u l t ) ; Py_DECREF( i t e m ) ; r e t u r n NULL ; } PyObject ∗nw = PyNumber_Add ( result , field ); Py_DECREF( r e s u l t ) ; ...
  49. 49. Ужас d e f sum_th ( l s t ) : result = 0 for i in l s t : #! r e s u l t += i . t h #!!!111 return result Это гораздо проще!
  50. 50. Cython Откомпилировав пример в Cython, я получил следующие результаты: Python код 14 830 C-код, C строка 16 636 С-код, встроенная строка 8 862 Cython код 7 067
  51. 51. Выводы догнать Python’ом C не получиться; можно потерять 20% просто так; активно используя Cython можно неплохо ускорить программу; и мало потерять в выразительности.
  52. 52. Спасибо за внимание.
  53. 53. Вопросы?

×