Ответ 1
Я обнаружил, что вы можете это сделать:
prof = cProfile.Profile()
retval = prof.runcall(self.method_actual, *args, **kwargs)
prof.dump_stats(datafn)
Недостатком является то, что он недокументирован.
Я пытаюсь профилировать метод экземпляра, поэтому я сделал что-то вроде:
import cProfile
class Test():
def __init__(self):
pass
def method(self):
cProfile.runctx("self.method_actual()", globals(), locals())
def method_actual(self):
print "Run"
if __name__ == "__main__":
Test().method()
Но теперь проблемы возникают, когда я хочу, чтобы "метод" возвращал значение, которое вычисляется методом "method_actual". Я действительно не хочу дважды называть метод method_actual.
Есть ли другой способ, который может быть потокобезопасным? (В моем приложении данные cProfile сохраняются в файлах данных, названных одним из аргументов, поэтому они не сбрасываются, и я могу их комбинировать позже.)
Я обнаружил, что вы можете это сделать:
prof = cProfile.Profile()
retval = prof.runcall(self.method_actual, *args, **kwargs)
prof.dump_stats(datafn)
Недостатком является то, что он недокументирован.
Опция для любого произвольного кода:
import cProfile, pstats, sys
pr = cProfile.Profile()
pr.enable()
my_return_val = my_func(my_arg)
pr.disable()
ps = pstats.Stats(pr, stream=sys.stdout)
ps.print_stats()
Взято из https://docs.python.org/2/library/profile.html#profile.Profile
Я боролся с той же проблемой и использовал функцию-оболочку для получения значений прямого возврата. Вместо
cP.runctx("a=foo()", globals(), locales())
Я создаю функцию-обертку
def wrapper(b):
b.append(foo())
и профилировать вызов функции-обертки
b = []
cP.runctx("wrapper(b)", globals(), locals())
a = b[0]
извлечение результата вычисления foo из параметра out (b) впоследствии.
Я думаю, @detly .runcall()
- это в основном лучший ответ, но для полноты я просто хотел, чтобы ответ @ThomasH был независимым от функции:
def wrapper(b, f, *myargs, **mykwargs):
try:
b.append(f(*myargs, **mykwargs))
except TypeError:
print 'bad args passed to func.'
# Example run
def func(a, n):
return n*a + 1
b = []
cProfile.runctx("wrapper(b, func, 3, n=1)", globals(), locals())
a = b[0]
print 'a, ', a
Я создал декоратор:
import cProfile
import functools
import pstats
def profile(func):
@functools.wraps(func)
def inner(*args, **kwargs):
profiler = cProfile.Profile()
profiler.enable()
try:
retval = func(*args, **kwargs)
finally:
profiler.disable()
with open('profile.out', 'w') as profile_file:
stats = pstats.Stats(profiler, stream=profile_file)
stats.print_stats()
return retval
return inner
Украсьте свою функцию или метод:
@profile
def somefunc(...):
...
Теперь эта функция будет профилирована.
В качестве альтернативы, если вам нужны необработанные необработанные данные профиля (например, потому что вы хотите запустить отличный графический просмотрщик RunSnakeRun на нем), выполните следующие действия:
import cProfile
import functools
import pstats
def profile(func):
@functools.wraps(func)
def inner(*args, **kwargs):
profiler = cProfile.Profile()
profiler.enable()
try:
retval = func(*args, **kwargs)
finally:
profiler.disable()
profiler.dump_stats('profile.out')
return retval
return inner
Это небольшое улучшение по нескольким другим ответам на этой странице.