[cython] разбор простой задачи
Не такой чтобы уж спец по cpython/cython, но кое-что бросается в глаза. времени в обрез - так что только тезисно.
1) для такой задачи лучше подойдет numpy - с лету сказать сложно, но подходящий функционал в нем есть. в scipy возможно даже готовая функция найдется. для примера можно и самому проимплементировать - ок, идем дальше
2) зачем тут dict? это неупорядоченная структура для хранение разнотипных данных. тут больше уместен простой list - как по функциональности, так и по самому решению. с list этот же пример будет читаться лучше и выполняться быстрее.
3) ну ладно уж, взяли dict, идем дальше. а что дальше - пробегаемся по нему полностью (еще раз - это дорогая в смысле производительности структура данных) чтобы суммировать, а затем второй раз тоже до какого-то места и тоже суммируя! чтобы стало быстрее надо очевидно изменить алгоритм таким образом чтобы пробегаться было достаточно только один раз. посчитать как это влияет можно на примерах типа {1:1, 2:1, 3:1, 4:1, 5:95} {1:1, 2:1, 3:95, 4:1, 5:1} , {1:95, 2:1, 3:1, 4:1, 5:1}. Для какого то из этих примеров (насколько помню, dict не гарантирует порядка данных, поэтому нельзя сказать наперед для какого именно) второй цикл будет отрабатываться быстрей всего, для какого-то дольше всего. Из этой разницы можно оценить какой вклад вносит доступ к элементу dict в общее время выполнения.
так что общее направление оптимизации (если без применения сторонней библиотеки типа numpy/scipy) - это переписать с использованием list с одновременным уменьшением числа пробегов по нему. как именно - ну надо думать.
сам пример - скорей на тему как не стоит делать. этот якобы cython код на самом деле дергает очень много cpython, поэтому и переписывание дает мало. для полноты картины - сравнивать надо бы на больших объемах данных, а не только на большом количестве итераций.
и да - если я выше где-то облажался, прошу считать меня ни на что не претендующим ньюбом
1) для такой задачи лучше подойдет numpy - с лету сказать сложно, но подходящий функционал в нем есть. в scipy возможно даже готовая функция найдется. для примера можно и самому проимплементировать - ок, идем дальше
2) зачем тут dict? это неупорядоченная структура для хранение разнотипных данных. тут больше уместен простой list - как по функциональности, так и по самому решению. с list этот же пример будет читаться лучше и выполняться быстрее.
3) ну ладно уж, взяли dict, идем дальше. а что дальше - пробегаемся по нему полностью (еще раз - это дорогая в смысле производительности структура данных) чтобы суммировать, а затем второй раз тоже до какого-то места и тоже суммируя! чтобы стало быстрее надо очевидно изменить алгоритм таким образом чтобы пробегаться было достаточно только один раз. посчитать как это влияет можно на примерах типа {1:1, 2:1, 3:1, 4:1, 5:95} {1:1, 2:1, 3:95, 4:1, 5:1} , {1:95, 2:1, 3:1, 4:1, 5:1}. Для какого то из этих примеров (насколько помню, dict не гарантирует порядка данных, поэтому нельзя сказать наперед для какого именно) второй цикл будет отрабатываться быстрей всего, для какого-то дольше всего. Из этой разницы можно оценить какой вклад вносит доступ к элементу dict в общее время выполнения.
так что общее направление оптимизации (если без применения сторонней библиотеки типа numpy/scipy) - это переписать с использованием list с одновременным уменьшением числа пробегов по нему. как именно - ну надо думать.
сам пример - скорей на тему как не стоит делать. этот якобы cython код на самом деле дергает очень много cpython, поэтому и переписывание дает мало. для полноты картины - сравнивать надо бы на больших объемах данных, а не только на большом количестве итераций.
и да - если я выше где-то облажался, прошу считать меня ни на что не претендующим ньюбом

Ну, объективно я со всем написанным согласен. dict вообще сам по себе тяжелый (было интересно, даст ли прирост скорости объявление dict — дало). Плюс я убрал сортировку ключей (скорость падала в два раза что не правильно (хоть и сработало верно).
Касательно улучшения алгоритмов и типов — это следующий шаг (сравнить через list/array, попробовать vector).
Итерации тут больше для:
первичное: растяжения времени, чтобы наглядно видеть прирост скорости выполнения,
вторичное: провести большую выборку, чтобы наглядно убедиться в вероятности выпадения при единичном вызове.
scipy/numpy тоже в планах (тем более cython с numpy вообще на "ты" на первом этапе интересны средства "из коробки".
Сейчас меня волнует, правильно ли я "сатанизировал" православный Python, т.к. раньше подобного (конкретно с ним) делал.
Касательно улучшения алгоритмов и типов — это следующий шаг (сравнить через list/array, попробовать vector).
Итерации тут больше для:
первичное: растяжения времени, чтобы наглядно видеть прирост скорости выполнения,
вторичное: провести большую выборку, чтобы наглядно убедиться в вероятности выпадения при единичном вызове.
scipy/numpy тоже в планах (тем более cython с numpy вообще на "ты" на первом этапе интересны средства "из коробки".
Сейчас меня волнует, правильно ли я "сатанизировал" православный Python, т.к. раньше подобного (конкретно с ним) делал.
Запустил питоном - время 10 сек, запустил через pypy - 3.3 сек.
Строчек прибавилось 0, время сократилось в 3 раза
Строчек прибавилось 0, время сократилось в 3 раза

Тот же результат.
А статически типизированный код не завелся. Pypy скушал гигабайт памяти и прекратил работу.
Позже попробую более обдуманно собрать.
>>>> import _randoms
10.0 10.01
20.0 20.0
15.0 15.0
25.0 24.99
30.0 30.0
Time Taken: 0:00:03.480000
А статически типизированный код не завелся. Pypy скушал гигабайт памяти и прекратил работу.
Позже попробую более обдуманно собрать.
Мой опыт и с цитоном и со свигом весьма небольшой. Но я вот в упор не понимаю зачем нужен стрёмный диалект си с псевдопитоновым синтаксисом, когда есть нормальный си, а то и си++ и вполне себе mature SWIG чтобы к питону это присобачить. Единственное что приходит на ум - из цитона вроде как чуть проще дёргать питоновые сущности, ну и типа мигрировать постепенно. Но это очень редко же надо, в большинстве случаев performance-critical кусок находится внизу цепочки вызовов.
А если интерфейс простой, и обмен идёт только базовами типами, строками и сишными массивами, то вообще ничего не надо, есть ctypes.
Ну и как тут говорят если нужна не суперскорость а просто скорость, то можно pypy заюзать бесплатно.
Или если задача векторизуется то можно всё в numpy делать. И это не только к численным методам относится.
У цитона нет ниши.
Ы?
А если интерфейс простой, и обмен идёт только базовами типами, строками и сишными массивами, то вообще ничего не надо, есть ctypes.
Ну и как тут говорят если нужна не суперскорость а просто скорость, то можно pypy заюзать бесплатно.
Или если задача векторизуется то можно всё в numpy делать. И это не только к численным методам относится.
У цитона нет ниши.
Ы?
За время отпуска просто посетила мысль: какой будет прирост производительности, если провести статическую типизацию. Код написан, отлично работает. Будет ли профит, если задекларировать переменные, и есть ли готовые инструменты? Не я ж один такой умный, наверняка эта мысль посещала более творческие умы.
Гуглинг по фразе "static typed python" вывел на цитон.
Почитал доки, сел вчера написать хрень из первого поста. Безрассудная фигачилка типов дала прирост в два раза.
Как я к этому отношусь, пока не решил. Между 12 и 5 сек разница существенная, но между
и
не особо велика.
Нужно разобрать больше примеров, имеющих отношение к сфере деятельности, чтобы прийти к заключению. Но сперва надо понять, всё ли правильно объявлено тут или упустил чего.
И да, возможно, я нагуглил не тот инструмент для анализа.
Гуглинг по фразе "static typed python" вывел на цитон.
Почитал доки, сел вчера написать хрень из первого поста. Безрассудная фигачилка типов дала прирост в два раза.
Как я к этому отношусь, пока не решил. Между 12 и 5 сек разница существенная, но между
Нужно разобрать больше примеров, имеющих отношение к сфере деятельности, чтобы прийти к заключению. Но сперва надо понять, всё ли правильно объявлено тут или упустил чего.
И да, возможно, я нагуглил не тот инструмент для анализа.
Между 12 и 5 сек разница существенная, но между ... и ... не особо велика.вообще-то одинаковая - в 2.4 раза
Не ясно выразился. В плане человеческого ожидания.
Отказ от dict
В православном время выполнения не поменялось, в собранном дало прирост 4х.
pypy всех сделал.
Прошелся по Гуглу чуть ниже первых строк. Оказывается, сам Г. ван Россум думает от статической типизации.
Касательно цитона я так понял, основная (полезная) идея в доступе из Py2, Py3 и C. Пригодится, если появится необходимость перейти с версии 2 на 3.
А пока, да, достаточно pypy. Спасибо отозвавшимся.
# _randoms.py
from random import random
from datetime import datetime
def takeone(l):
rnd = random * sum(l)
boundary = 0
for i in range(len(l:
boundary += l[i]
if rnd < boundary:
return i
values = ['ru','us','en','de','fr']
chances = [ 10, 20, 15, 25, 30 ]
results = [0 for i in chances]
r = 10**7
start = datetime.now
for i in range(r):
results[takeone(chances)] += 1
end = datetime.now
for i in range(len(chances:
print values[i], round(100.0*chances[i]/sum(chances 2 round(100.0*results[i]/sum(results 2)
print 'Time Taken: %s'%(end-start)
# randoms.pyx
from random import random
from datetime import datetime
def takeone(list l):
cdef:
int i
float rnd = random * sum(l)
int boundary = 0
for i in range(len(l:
boundary += l[i]
if rnd < boundary:
return i
cdef:
int i
list values = ['ru','us','en','de','fr']
list chances = [ 10, 20, 15, 25, 30 ]
list results = [0 for i in chances]
int r = 10**7
start = datetime.now
for i in range(r):
results[takeone(chances)] += 1
end = datetime.now
for i in range(len(chances:
print values[i], round(100.0*chances[i]/sum(chances 2 round(100.0*results[i]/sum(results 2)
print 'Time Taken: %s'%(end-start)
В православном время выполнения не поменялось, в собранном дало прирост 4х.
>>> import _randoms
ru 10.0 10.01
us 20.0 19.99
en 15.0 15.0
de 25.0 25.01
fr 30.0 29.99
Time Taken: 0:00:12.190000
>>> import randoms
ru 10.0 9.99
us 20.0 20.01
en 15.0 15.01
de 25.0 24.97
fr 30.0 30.01
Time Taken: 0:00:03.080000
pypy всех сделал.
>>>> import _randoms
ru 10.0 10.0
us 20.0 19.97
en 15.0 15.01
de 25.0 25.0
fr 30.0 30.02
Time Taken: 0:00:01.758000
Прошелся по Гуглу чуть ниже первых строк. Оказывается, сам Г. ван Россум думает от статической типизации.
Касательно цитона я так понял, основная (полезная) идея в доступе из Py2, Py3 и C. Пригодится, если появится необходимость перейти с версии 2 на 3.
А пока, да, достаточно pypy. Спасибо отозвавшимся.
У нас сейчас вычисления на питоне делаются через pypy+numpy.
Сишные куски мы пробовали делать пару лет назад, итог неутешителен - прирост производительности в пару раз, зато оптимизировать получающуюся кашу очень сложно.
cython в принципе не придумали зачем нужен.
Сишные куски мы пробовали делать пару лет назад, итог неутешителен - прирост производительности в пару раз, зато оптимизировать получающуюся кашу очень сложно.
cython в принципе не придумали зачем нужен.
Но я вот в упор не понимаю зачем нужен стрёмный диалект си с псевдопитоновым синтаксисом, когда есть нормальный си, а то и си++ и вполне себе mature SWIG чтобы к питону это присобачить.Использовать cython для биндинга C кода проще и удобнее.
Оставить комментарий
khachin
Решил тут поиграться со статической типизацией. Задачу взял .Вышло нечто такое:
Запускаем в среде:
Строк прибавилось на 7, время сократилось более, чем в 2 раза.
У кого есть опыт в "сатанизации"? Что еще можно улучшить конкретно в данном примере?
Оффтоп: На Galaxy Note 3 в qpython выполнение исходного скрипта заняло 0:01:09.640000