python
June 5, 2021

Тайм-менеджмент с Python

Без оптимизации времени выполнения кода при работе с данными большого размера никак не обойтись. Расскажем, какие существуют простые методы измерения скорости выполнения строк, функций и сценариев в Python.

Создадим датафрейм:

import pandas as pd
import numpy as np
data = np.random.normal(size=(5000000,3))
df = pd.DataFrame(data, columns=['first', 'second', 'third'])

Теперь перейдем к измерениям. Во-первых, время работы участка кода можно оценивать с помощью встроенных модулей:

import time
start = time.time()
df_sum = df.sum(axis=1)
end = time.time()
print(f'Затраченное время составило {end-start} сек')

Но наиболее удобные средства для этого предоставляет командная оболочка IPython, устанавливаемая как пакет в окружение интерпретатора и совместимая с популярными средами разработки - PyCharm, Jupyter, Spyder.

Время выполнения строк

В частности, для достижения той же цели можно воспользоваться магическими командами %time, %timeit (разница в том, что во второй для объектиности вычисляется среднее время нескольких итераций):

%time df.sum(axis=1)
%timeit df.sum(axis=1)

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

Время выполнения блоков

Если вызывать магические команды с двумя символами процента, то происходит измерение времени выполнения блоков:

%%time
df_new = df.copy()
for i, row in df_new.iterrows():
    if i<5:
        df_new.at[i, 'first'] = i

Профилирование сценариев

Посредством профилирования устанавливается время исполнения различных участков кода. В Python основное средство для этого – встроенный модуль cProfile.

Напишем небольшой скрипт и сохраним в файле :

def f_minus(a,b):
    return a-b

def f_plus(a,b):
    return a+b

c = [f_minus(3,4) for _ in range(10000)]
d = [f_plus(1,3) for _ in range(20000)]

Ниже пример вызова профилирования сценария с флагом упорядочивания по времени исполнения:

python -m cProfile -s cumulative time_script.py

IPython предусматривает магические команды для более удобного применения cProfile. Так для получения схожих результатов можно применить %run с ключом -p:

%run -p -s cumulative time_script.py

Профилирование функций

С помощью магической команды %prun можно осуществить профилирование функции. Добавим в сценарий функцию:

def f_ops():
    c = [f_minus(3,4) for _ in range(100000)]
    d = [f_plus(1,3) for _ in range(200000)]

теперь инициируем профилирование:

from time_script import f_ops
%prun -s cumulative f_ops()

Результат показывает сколько времени тратится на вызов "подфункций".

Пошаговое профилирование функции

Для этого устанавливаем пакет:

pip install line_profiler   

Далее загружаем расширение в оболочку (иначе получим ошибку):

%load_ext line_profiler

Теперь инициируем профилирование:

%lprun -f f_ops f_ops()