使用 cProfile 时的返回值
Posted
技术标签:
【中文标题】使用 cProfile 时的返回值【英文标题】:Return value while using cProfile 【发布时间】:2009-10-18 09:04:26 【问题描述】:我正在尝试分析一个实例方法,所以我做了类似的事情:
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”两次。
还有其他方法,可以是线程安全的吗? (在我的应用程序中,cProfile 数据保存到由其中一个 args 命名的数据文件中,因此它们不会被破坏,我可以稍后将它们组合起来。)
【问题讨论】:
【参考方案1】:我发现你可以这样做:
prof = cProfile.Profile()
retval = prof.runcall(self.method_actual, *args, **kwargs)
prof.dump_stats(datafn)
缺点是它没有记录。
【讨论】:
太棒了!这看起来很完美 - 但什么是“datafn”? @JonathanHartley - 数据文件 IIRC 的文件名。 啊,谢谢。我认为“fn”是指函数,而不是文件名。 @Ngoral 这只是一个文件名。你可以把任何你喜欢的名字放在那里。 @Ngoral 不用担心,我应该在答案中澄清【参考方案2】:任意代码的选项:
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
【讨论】:
您甚至可以使用contextlib
s contextmanager
装饰器为此创建一个小的上下文管理器。
我收到Random listing order was used
- 我如何指定上市顺序?
ps.sort_stats('cumulative')
如何使用此方法生成有效的配置文件,以便可以将其与 SnakeViz 一起使用
我只会添加类似:ps.dump_stats('my_dumpfile.dmp') 这样就可以使用snakeviz 或类似工具来查看结果,否则这对我来说非常有用!在此之前,我在获取我的返回值时度过了一段愉快的时光。【参考方案3】:
我在同样的问题上苦苦挣扎,并使用了一个包装函数来克服直接返回值。而不是
cP.runctx("a=foo()", globals(), locales())
我创建了一个包装函数
def wrapper(b):
b.append(foo())
并分析对包装函数的调用
b = []
cP.runctx("wrapper(b)", globals(), locals())
a = b[0]
之后从 out 参数 (b) 中提取 foo 的计算结果。
【讨论】:
【参考方案4】:我创建了一个装饰器:
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
这是对本页上其他几个答案的微小改进。
【讨论】:
【参考方案5】:我认为@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
【讨论】:
以上是关于使用 cProfile 时的返回值的主要内容,如果未能解决你的问题,请参考以下文章