Обычно я использую команду оболочки time
. Моя цель - проверить, являются ли данные маленькими, средними, большими или очень большими, сколько времени и памяти будет.
Любые инструменты для linux или просто python для этого?
Обычно я использую команду оболочки time
. Моя цель - проверить, являются ли данные маленькими, средними, большими или очень большими, сколько времени и памяти будет.
Любые инструменты для linux или просто python для этого?
Посмотрите timeit, профайлер python и pycallgraph.
def test():
"""Stupid test function"""
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
По существу, вы можете передать код python в виде строкового параметра, и он будет выполняться в указанное количество раз и печатает время выполнения. Важные биты из документов:
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
Создайте экземпляр
Timer
с данным оператором, установите кода и таймера и запустить его методtimeit
с помощью число исполнений.
... и:
Timer.timeit(number=1000000)
Выполнение номеров времени основного оператора. Это выполняет настройку один раз, а затем возвращает время, необходимое для выполнения основного несколько раз, измеряемый в секундах как поплавок. Аргумент - это количество раз через цикл, по умолчанию - один млн. Основной оператор, инструкция установки и функция таймера которые будут использоваться, передаются конструктору.
Примечание
По умолчанию
timeit
временно отключаетgarbage collection
во время синхронизации. Преимущество такого подхода состоит в том, что он делает независимые тайминги более сопоставимыми. Этот недостаток что ГК может быть важным компонентом измеряемая функция. Если это так, GC можно снова включить в качестве первого в строке настройки. Например:
timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()
Профилирование даст вам более подробное представление о том, что происходит. Здесь "мгновенный пример" из официальных документов:
import cProfile
import re
cProfile.run('re.compile("foo|bar")')
Что вам даст:
197 function calls (192 primitive calls) in 0.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.001 0.001 <string>:1(<module>)
1 0.000 0.000 0.001 0.001 re.py:212(compile)
1 0.000 0.000 0.001 0.001 re.py:268(_compile)
1 0.000 0.000 0.000 0.000 sre_compile.py:172(_compile_charset)
1 0.000 0.000 0.000 0.000 sre_compile.py:201(_optimize_charset)
4 0.000 0.000 0.000 0.000 sre_compile.py:25(_identityfunction)
3/1 0.000 0.000 0.000 0.000 sre_compile.py:33(_compile)
Оба этих модуля должны дать вам представление о том, где искать узкие места.
Кроме того, чтобы получить доступ к выходу profile
, посмотрите этот пост
Этот модуль использует graphviz для создания callgraphs, таких как:
Вы можете легко увидеть, какие пути использовали наибольшее время по цвету. Вы можете создать их с помощью API pycallgraph или с помощью упакованного script:
pycallgraph graphviz -- ./mypythonscript.py
Накладные расходы довольно значительны. Поэтому для уже длительных процессов создание графика может занять некоторое время.
Я использую простой декоратор, чтобы время func
def st_time(func):
"""
st decorator to calculate the total time of a func
"""
def st_func(*args, **keyArgs):
t1 = time.time()
r = func(*args, **keyArgs)
t2 = time.time()
print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
return r
return st_func
Модуль timeit
был медленным и странным, поэтому я написал это:
def timereps(reps, func):
from time import time
start = time()
for i in range(0, reps):
func()
end = time()
return (end - start) / reps
Пример:
import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)
Для меня это говорит:
python can do 40925 os.listdir('/') per second
Это примитивный вид бенчмаркинга, но он достаточно хорош.
Я обычно делаю быстрый time ./script.py
, чтобы узнать, сколько времени потребуется. Это не показывает вам память, хотя, по крайней мере, не по умолчанию. Вы можете использовать /usr/bin/time -v ./script.py
для получения большой информации, включая использование памяти.
Посмотрите nose и на один из своих плагинов этот.
После установки нос - это script на вашем пути, и вы можете вызвать в каталоге, который содержит некоторые скрипты python:
$: nosetests
Это будет выглядеть во всех файлах python в текущем каталоге и будет выполнять любую функцию, которую он распознает как тест: например, он распознает любую функцию со словом test_ в своем имени в качестве теста.
Итак, вы можете просто создать python script, называемый test_yourfunction.py, и написать в нем что-то вроде этого:
$: cat > test_yourfunction.py
def test_smallinput():
yourfunction(smallinput)
def test_mediuminput():
yourfunction(mediuminput)
def test_largeinput():
yourfunction(largeinput)
Затем вам нужно запустить
$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py
и чтобы прочитать файл профиля, используйте эту строку python:
python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"
Профилировщик памяти для всех ваших потребностей в памяти.
https://pypi.python.org/pypi/memory_profiler
Запустите настройку pip:
pip install memory_profiler
Импортировать библиотеку:
import memory_profiler
Добавьте декоратор к элементу, который вы хотите просмотреть:
@profile
def my_func():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
del b
return a
if __name__ == '__main__':
my_func()
Выполнить код:
python -m memory_profiler example.py
Получить результат:
Line # Mem usage Increment Line Contents
==============================================
3 @profile
4 5.97 MB 0.00 MB def my_func():
5 13.61 MB 7.64 MB a = [1] * (10 ** 6)
6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7)
7 13.61 MB -152.59 MB del b
8 13.61 MB 0.00 MB return a
Примеры из документов, связанных выше.
Будьте осторожны timeit
очень медленно, это займет 12 секунд на моем среднем процессор просто инициализировать (или, возможно, запустить функцию). Вы можете проверить этот принятый ответ
def test():
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second
для простоты вместо этого я буду использовать time
, на моем компьютере он вернет результат 0.0
import time
def test():
lst = []
for i in range(100):
lst.append(i)
t1 = time.time()
test()
result = time.time() - t1
print(result) # 0.000000xxxx
Самый простой способ быстро протестировать любую функцию - использовать этот синтаксис: %timeit my_code
Например:
%timeit a = 1
13.4 ns ± 0.781 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)