gpt4 book ai didi

python - cProfile 和 profile 的区别——为什么没有 profile.Profile.enable() 方法?

转载 作者:行者123 更新时间:2023-12-04 17:44:04 30 4
gpt4 key购买 nike

在 Python 2.7 和 Python 3.6 中,我发现这有效:

from cProfile import Profile; p = Profile(); p.enable()
...而这引发了一个异常(exception):
from profile import Profile; p = Profile(); p.enable()

# --> AttributeError: 'Profile' object has no attribute 'enable'
这让我感到惊讶,因为我认为(以及 Python 3Python 2 状态的官方文档)这两个模块应该提供相同的程序员接口(interface):

Both the profile and cProfile modules provide the following functions:

...

class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)

...

enable()

Start collecting profile data.


我错过了什么?使用 profile.Profile() 的正确方法是什么?实例?

最佳答案

截至 Python 3.8和更新的文档,他们已修复此问题以指定 enable()disable()仅适用于 cProfile .与 profile.Profile ,您需要使用 run()enable() 相对的调用和 disable() .以下是每个示例:
cProfile.Profile:

# cProfile.Profile -- control with enable() and disable()
from datetime import datetime
import cProfile, pstats, io
sortby = 'cumulative'
pr1 = cProfile.Profile(lambda: int(datetime.now().timestamp()*1000000), 0.000001)
pr1.enable()
list(x for x in range(int(10*10*10*10/10*10+10)))
pr1.disable()
s1 = io.StringIO()
ps1 = pstats.Stats(pr1, stream=s1).sort_stats(sortby)
ps1.print_stats()
print(s1.getvalue())
个人资料。个人资料:
# profile.Profile -- control with run()
from datetime import datetime
import profile, pstats, io
sortby = 'cumulative'
pr2 = profile.Profile(datetime.now().timestamp, 0.000001)
pr2.run('list(x for x in range(int(10*10*10*10/10*10+10)))')
s2 = io.StringIO()
ps2 = pstats.Stats(pr2, stream=s2).sort_stats(sortby)
ps2.print_stats()
print(s2.getvalue())
以下是我在两种形式之间观察到的一些行为差异:
  • cProfile将分析函数的输出推送到标准输出,而 profile将不会。
  • 最终报告的filename:lineno(function)列的输出略有不同。 cProfile一般会更易读地显示内置函数。
  • 然而,在我这里提供的示例中,传入的函数实际上可以在 profile 中识别。的输出而不是在 cProfile 's -- 但如果使用命名函数,它在两个分析器的输出中都是可识别的(尽管传递给函数的参数只能从 profile 的输出中看到)。

  • 通过两者运行相同的功能 cProfileprofile提供略有不同的结果。好像cProfile通常会生成大约两个更少的函数调用,并且将为相同的函数提供更有效的时间。
  • 使用分析器的可选自定义 timertimeunit参数可以提供获得微秒精度与默认毫秒精度的好处。但是,似乎尝试使用这些带有一些警告:
  • cProfile的 timeunit 函数需要一个整数,而 profile需要一个浮点数。这意味着您不能使用 datetime.now().timestamp()直接与 cProfile ,但必须先将其包装在 lambda 中以将其转换为完整整数。
  • 此外,由于某种原因 profile datetime.now().timestamp() 似乎不能正常工作即使这是它所期望的格式。它将打印出负时间值——我在下面展示了这一点。切换到 lambda 形式以将其转换为整数无济于事,如 profile期望浮点数。

  • 以下是 profile.Profile 的输出与 datetime.now().timestamp()用于微秒设置的计时器。
     print(s2.getvalue())
    10015 function calls in -0.020 seconds`

    Ordered by: cumulative time

    ncalls tottime percall cumtime percall filename:lineno(function)
    0 0.000 0.000 profile:0(profiler)
    1 0.000 0.000 0.000 0.000 :0(setprofile)
    10011 -0.010 -0.000 -0.010 -0.000 <string>:1(<genexpr>)
    1 -0.010 -0.010 -0.020 -0.020 <string>:1(<module>)
    1 -0.000 -0.000 -0.020 -0.020 :0(exec)
    1 -0.000 -0.000 -0.020 -0.020 profile:0(list(x for x in range(int(10*10*10*10/10*10+10))))
  • 然而,这个问题可以通过提供一个自定义的计时器函数来解决(它甚至可以环绕 datetime.now() 以提供与 datetime.now().timestamp() 完全相同的输出格式),原因我无法解释。

  • 例如如果我们定义:
    def timenow():
    now = datetime.now()
    return (((now.year-1970) * 31557600) + (now.month * 2629800) +
    (now.day * 86400) + (now.hour * 3600) + (now.minute * 60) +
    now.second + (now.microsecond * 0.000001))
    我们现在可以使用 pr2 = profile.Profile(timenow, 0.000001) ,这将输出以下(理智的)报告:
    >>> print(s2.getvalue())
    10015 function calls in 0.041 seconds

    Ordered by: cumulative time

    ncalls tottime percall cumtime percall filename:lineno(function)
    1 0.006 0.006 0.041 0.041 profile:0(list(x for x in range(int(10*10*10*10/10*10+10))))
    1 0.000 0.000 0.035 0.035 :0(exec)
    1 0.017 0.017 0.035 0.035 <string>:1(<module>)
    10011 0.018 0.000 0.018 0.000 <string>:1(<genexpr>)
    1 0.001 0.001 0.001 0.001 :0(setprofile)
    0 0.000 0.000 profile:0(profiler)
    cProfile的输出比较(使用上面定义的自定义 lambda 计时器),我们有:
    >>> print(s1.getvalue())
    10013 function calls in 0.031 seconds

    Ordered by: cumulative time

    ncalls tottime percall cumtime percall filename:lineno(function)
    10011 0.031 0.000 0.031 0.000 <stdin>:1(<genexpr>)
    1 0.000 0.000 0.000 0.000 <stdin>:1(<module>)
    1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
    至于为什么我们的自定义计时器函数给出了合理的结果和 datetime.now().timestamp()不与 profile ,首先要说明的是 timenow不提供时间给 datetime.now().timestamp() .尽管它提供了接近纪元的时间,但它的偏差很小(不会影响正常的配置文件运行,因为增量在同一系统上是相同的)。 timenow中使用的手动转换也肯定不如 datetime.now().timestamp() 有效.我只能推测后者效率太高,而且 profile 不知何故。结果,源代码没有正确测量。
    TL; 博士
    使用 cProfile除非你有特定的理由不这样做。官方 Python 文档还指出推荐的模块是 cProfile .尽管没有提供具体的理由,文档似乎暗示 cProfile可能表现更好并适合大多数用户的目的(即使它是一种稍微冗长的语法)。

    关于python - cProfile 和 profile 的区别——为什么没有 profile.Profile.enable() 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52998945/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com