ζ༼Ɵ͆ل͜Ɵ͆༽ᶘ

Ускоряем Python

0 комментов
03.08.2020
2 мин чтения

Тесты, тесты, тесты

Измеряемо = Управляемо

Казалось бы, тест производительности занимает слишком много времени. Но когда ваш код уже разделён на функции, можно просто добавить декоратор (По сути функцию от функции) к измеряемой.

Сначала установим библиотеку line_profiler. Ей мы определим время, затраченное на каждую строку кода в функции:

pip3 install line_profiler

Теперь у нас есть декоратор @profile. Например, замерим им производительность такой функции:

 #имя файла: test.py

@profile
def sum_of_lists(ls):

    '''Суммирует введённые вложенные списки'''
    s = 0
    for l in ls:
        for val in l:
            s += val 

    return s

#создаём вложенные списки
smallrange = list(range(10000))
inlist = [smallrange, smallrange, smallrange, smallrange]

#и суммируем их
list_sum = sum_of_lists(inlist)

print(list_sum)
 ```

Это вызовет функцию ==sum_of_lists== и протестирует её производительность. Обратите внимание на декоратор ==@profile== перед объявлением функции. Сейчас код можно профилировать так:

```py3
python3 -m line_profiler test.py

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


Никаких циклов

В большинстве случаев лучше использовать map, представления списков или numpy.vectorize. Ведь эти операции уже многократно оптимизированы. Слегка изменим нашу функцию и заменим внутренние циклы на map и sum:

#имя файла: test.py

@profile
def sum_of_lists(ls):

    '''Суммирует введённые вложенные списки'''
    return(sum(list(map(sum,ls))))



#создаём вложенные списки
smallrange = list(range(10000))
inlist = [smallrange, smallrange, smallrange, smallrange]

#и суммируем их
list_sum = sum_of_lists(inlist)

print(list_sum)
Сравним производительность до и после:

Используем Cython

Не хотите менять код, но хочется, чтобы работало быстрее? Тогда Cython для вас. Хотя Cython и не является универсальным компилятором из Python в C, он всё равно способен компилировать модули Python в общие объектные файлы (.so), которые загрузит ваш основной скрипт. Для этого нужно установить Cython и компилятор C:

pip3 install cython

Если у вас Windows, то компилятор можно скачать отсюда:

Если у вас Linux, то gcc устанавливается следующей командой в терминале:

sudo apt install gcc

Разделим наш пример на 2 файла с именами test_cython.py и test_module.pyx:

#имя файла: test_module.pyx

def sum_of_lists(ls):

    '''Суммирует введённые вложенные списки'''
    s = 0
    for l in ls:
        for val in l:
            s += val
    return s

Наш основной файл должен импортировать эту функцию из файла test_module.pyx:

#имя файла: test_cython.py
from test_module import *

# создаём вложенные списки
smallrange = list(range(10000))
inlist = [smallrange,smallrange,smallrange,smallrange]

# и суммируем их
list_sum = sum_of_lists(inlist)

print(list_sum)

Теперь давайте определим файл setup.py для компиляции нашего модуля с использованием Cython:

#имя файла: setup.py
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("test_module.pyx")
)

Время компилировать модуль:

 python3 setup.py build_ext –inplace

Сравним производительность:

Быстрее оригинала только в 2 раза, но всё зависит от конкретного кода, который вы скармливаете Cython.

Сегодня мы рассмотрели 3 способа улучшения производительности вашего кода. Но самое важное – изначально писать правильный и экономичный код. Тогда и ускорять не понадобится.

4
Сегодня
День улёта