Есть ли простой способ сравнения python script?
Обычно я использую команду оболочки time
. Моя цель - проверить, являются ли данные маленькими, средними, большими или очень большими, сколько времени и памяти будет.
Любые инструменты для linux или просто python для этого?
Ответы
Ответ 1
Посмотрите timeit, профайлер python и pycallgraph.
timeit
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
, посмотрите этот пост
pycallgraph
Этот модуль использует graphviz для создания callgraphs, таких как:
![callgraph example]()
Вы можете легко увидеть, какие пути использовали наибольшее время по цвету. Вы можете создать их с помощью API pycallgraph или с помощью упакованного script:
pycallgraph graphviz -- ./mypythonscript.py
Накладные расходы довольно значительны. Поэтому для уже длительных процессов создание графика может занять некоторое время.
Ответ 2
Я использую простой декоратор, чтобы время 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
Ответ 3
Модуль 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
Это примитивный вид бенчмаркинга, но он достаточно хорош.
Ответ 4
Я обычно делаю быстрый time ./script.py
, чтобы узнать, сколько времени потребуется. Это не показывает вам память, хотя, по крайней мере, не по умолчанию. Вы можете использовать /usr/bin/time -v ./script.py
для получения большой информации, включая использование памяти.
Ответ 5
Посмотрите 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)"
Ответ 6
Профилировщик памяти для всех ваших потребностей в памяти.
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
Примеры из документов, связанных выше.
Ответ 7
Будьте осторожны 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
Ответ 8
Самый простой способ быстро протестировать любую функцию - использовать этот синтаксис: %timeit my_code
Например:
%timeit a = 1
13.4 ns ± 0.781 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)