Возвращаемое значение при использовании cProfile
Я пытаюсь профилировать метод экземпляра, поэтому я сделал что-то вроде:
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" возвращал значение, которое вычисляется "method_actual". Я действительно не хочу вызывать "method_actual" дважды.
Есть ли другой способ, который может быть потокобезопасным? (В моем приложении данные cProfile сохраняются в файлах данных, названных одним из аргументов, поэтому они не сгущаются, и я могу объединить их позже.)
5 ответов
Я обнаружил, что вы можете сделать это:
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()
Я боролся с той же проблемой и использовал функцию-обертку, чтобы преодолеть прямые возвращаемые значения. Вместо
cP.runctx("a=foo()", globals(), locales())
Я создаю функцию-обертку
def wrapper(b):
b.append(foo())
и профилировать вызов функции оболочки
b = []
cP.runctx("wrapper(b)", globals(), locals())
a = b[0]
извлечение результата вычисления foo из выходного параметра (b) впоследствии.
Я создал декоратор:
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
Это незначительное улучшение некоторых других ответов на этой странице.
Я думаю, что @ .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