使用 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

【讨论】:

您甚至可以使用 contextlibs 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 时的返回值的主要内容,如果未能解决你的问题,请参考以下文章

计算平均值时的意外返回值?

大型nvarchar2值返回时的oracle存储过程错误

Flux 完成时的返回值?

Ajax详解及使用Ajax时的返回值类型有哪些?

分区时的情况 - 组的同一列中具有两个特定值的组的返回值

JsonResult作为Action返回值时的错误