В своем докладе Олег расскажет о замене стандартных функций на более быстрые и об ускорении работы python. Также продемонстрирует несколько примеров быстрых конструкций python.
2. Циклы
val = 0
i = 0
while i < 10000:
val += i
i += 1
from functools import reduce
reduce(lambda res, x: res+x, range(10000))
val = 0
for i in range(10000):
val += i
val = 0
for i in xrange(10000):
val += i
744 мс.
0.883 мс.
0.415 мс.
0.322 мс.
4. Список / Словарь
a = [i for i in range(100000)]
a = [0]*100000
for i in a:
a[i] = i
a = []
for i in range(100000):
a = a + [i]
a = []
for i in range(100000):
a += [i]
a = []
for i in range(100000):
a.append(i)
a = []
append = a.append
for i in range(100000):
append(i)
8.9 мс
10.2 мс
37000 мс (37 с.)
14.2 мс
8.8 мс
6.03 мс
5. Список / Словарь
words = ['asjasjd', 'akaksd', 'ajskskd', 'kasald']
a = {}
for word in words:
if word not in a:
a[word] = 0
a[word] += 1
a = {}
for word in words:
try:
a[word] += 1
except KeyError:
a[word] = 1
a = {}
get = a.get
for word in words:
a[word] = get(word, 0) + 1
852 нс
1600 нс
681 нс
6. Арифметические операции
pow(3, 30)
3 ** 30
math.sqrt(144)
144 ** .5
k = 1000
k >> 1
k / 2
k << 1
k * 2
189 нс
16.2 нс
68.3 нс
15.8 нс
Python 2 Python 3
39 нс
52.3 нс
38 нс
50.3 нс
65.6 нс
49.9 нс
68.8 нс
45.1 нс
9. Пример задачи
Задан массив чисел. И поступила n запросов найти сумму от l до r.
Очевидный вариант:
s = 0
for i in range(l, r+1):
s += a[i]
Продвинутый вариант:
sum(a[l:r+1])
Тест: 10000 элементов, n = 10
0.49 сек.
0.224 сек.
11. class Tree():
def __init__(self, a):
self.a = a
self.t = [0] * len(a)*4
self.build_tree(1, 0, len(self.a)-1)
def build_tree(self, v, l, r):
if l == r:
self.t[v] = self.a[l]
return self.t[v]
mid = (l+r) // 2
self.t[v] = self.build_tree(v*2, l, mid) + self.build_tree(v*2+1, mid+1, r)
return self.t[v]
def slice(self, v, l, r, tl, tr):
if l == tl and r == tr:
return self.t[v]
mid = (l+r) // 2
if tl >= l and tr <= mid:
return self.slice(v*2, l, mid, tl, tr)
if tl >= mid+1 and tr <= r:
return self.slice(v*2+1, mid+1, r, tl, tr)
return self.slice(v*2, l, mid, tl, mid) + self.slice(v*2+1, mid+1, r, mid+1, tr)
0.1 сек.
12. Пример задачи
Посчитать N-ое число Фибоначчи. (1, 1, 2, 3, 5, 8, 13 …. )
def fib(n):
a = 0
b = 1
for i in xrange(n):
a, b = b, a+b
return a
def fib2(n):
matrix = [[1, 1], [1, 0]]
return bin_pow(matrix, n+1)[1][1]
При n = 3000 При n = 10^7
370 мс.
43.4 мс.
25 мин.
89 мс.
13. cpmoptimize
from cpmoptimize import cpmoptimize
@cpmoptimize()
def fib(n):
a = 0
b = 1
for i in xrange(n):
a, b = b, a+b
return a
При n = 3000 При n = 10^7
368 мс. 13 сeк.
14. cpmoptimize
cpmoptimize.xrange(start, stop[, step])
cpmoptimize.cpmoptimize(strict=False, iters_limit=5000,
types=(int, long), opt_min_rows=True, opt_clear_stack=True)
Плюсы:
- ускоряет работу программы
- поддерживает большие типы данных
- легкий в использовании
- заботится о памяти
Минусы:
- оптимизирует только если все константы и переменные,
используемые в нём, имеют допустимый тип
- Тело цикла должно состоять только из инструкций присваивания, унарных
и бинарных операций
- Не может содержать условий, вызовов других функций, операторов return
и yield
15. Другие методы ускорения
1) PyPy — альтернативный интерпретатор Python с поддержкой JIT-компиляции
2) Pyston — новый альтернативный интерпретатор Python, транслирующий код
в промежуточное представление LLVM
3) Nuitka — компилятор Python. Умеет создавать exe файлы
4) astoptimizer — библиотека, применяющая известные методы оптимизации
перед компиляцией в байт-код путём анализа и изменения абстрактного
синтаксического дерева.
5) foldy.py — библиотека, анализирующая байт-код и выполняющая
сворачивание констант а также удаление неиспользуемых функций
6) Numba — библиотека, ускоряющая программы, содержащие математические
вычисления и операции с массивами. Оптимизация происходит за счёт JIT-
компиляции
7) Cython — оптимизирующий компилятор надмножества языка Python,
позволяющий использовать в программе статическую типизацию и тесно
взаимодействовать с кодом на C и C++.
16. Вывод
1) Если что-то можно заменить на встроенные функции – надо менять, т.к. VM
довольно медленная.
2) Будьте внимательны к типам, так как из-за них можно потерять скорость в 2-4
раза
3) Меньше глобальных переменных
4) Придумывайте алгоритмы
5) Если не смогли придумать пользуйтесь оптимизациями