我如何逐行分析Python代码?

roc*_*eys 104 python profiling line-by-line

我一直在使用cProfile来分析我的代码,它一直很好用.我还使用gprof2dot.py来显示结果(使其更清晰).

但是,cProfile(以及到目前为止我见过的大多数其他Python分析器)似乎只在函数调用级别进行分析.当从不同的地方调用某些函数时,这会引起混淆 - 我不知道呼叫#1或呼叫#2是否占用了大部分时间.当所讨论的函数深度为六级时,这会变得更糟,从其他七个地方调用.

如何进行逐行分析?

而不是这个:

function #12, total time: 2.0s
Run Code Online (Sandbox Code Playgroud)

我想看到这样的事情:

function #12 (called from somefile.py:102) 0.5s
function #12 (called from main.py:12) 1.5s
Run Code Online (Sandbox Code Playgroud)

cProfile确实显示了总共有多少时间"转移"到父级,但是当你有一堆层和互连的调用时,这种连接又会丢失.

理想情况下,我希望有一个GUI来解析数据,然后向我显示我的源文件,每个行的总时间.像这样的东西:

main.py:

a = 1 # 0.0s
result = func(a) # 0.4s
c = 1000 # 0.0s
result = func(c) # 5.0s
Run Code Online (Sandbox Code Playgroud)

然后我就可以点击第二个"func(c)"调用来查看该调用中占用的时间,与"func(a)"调用分开.

那有意义吗?是否有任何分析库收集此类信息?我错过了一些很棒的工具吗?

Joe*_*ton 111

我相信这就是Robert Kern的line_profiler的用途.从链接:

File: pystone.py
Function: Proc2 at line 149
Total time: 0.606656 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   149                                           @profile
   150                                           def Proc2(IntParIO):
   151     50000        82003      1.6     13.5      IntLoc = IntParIO + 10
   152     50000        63162      1.3     10.4      while 1:
   153     50000        69065      1.4     11.4          if Char1Glob == 'A':
   154     50000        66354      1.3     10.9              IntLoc = IntLoc - 1
   155     50000        67263      1.3     11.1              IntParIO = IntLoc - IntGlob
   156     50000        65494      1.3     10.8              EnumLoc = Ident1
   157     50000        68001      1.4     11.2          if EnumLoc == Ident1:
   158     50000        63739      1.3     10.5              break
   159     50000        61575      1.2     10.1      return IntParIO
Run Code Online (Sandbox Code Playgroud)

希望有所帮助!

  • line_profiler是否适用于Python 3?我无法获得任何相关信息. (9认同)
  • 任何人都可以展示如何实际使用这个库?自述文件教授如何安装和回答各种常见问题解答,但没有提到如何在pip安装后使用它. (7认同)
  • 这是我写的装饰者:https://gist.github.com/kylegibson/6583590.如果您正在运行nosetests,请务必使用-s选项,以便立即打印stdout. (6认同)
  • 生成此输出的python脚本如何?`import line_profiler;`然后呢? (4认同)
  • 乔,这正是我一直在寻找的。我可以只使用装饰器,将 LineProfiler() 对象附加到一些函数,它会逐行输出函数的配置文件。我真的希望有一种图形方式来查看结果,但这是一个很好的开始!谢谢! (2认同)
  • @Rocketmonkeys你愿意分享你的django装饰器吗? (2认同)
  • line_profiler没有为我显示点击次数和时间.谁能告诉我为什么?而如何解决? (2认同)
  • @user1251007:项目主页上的 [Changes](https://github.com/rkern/line_profiler#id11) 部分似乎表明它自 Python 3 自己的第一个非 beta 1.0 版本以来一直使用它。 (2认同)
  • **第 1 步:**,`pip install line_profiler` **第 2 步:** 在要分析的函数的脚本中,添加 `@profile` 装饰器 **第 3 步:** 运行此命令以生成 .lprof文件:`kernprof -l <​​您的脚本>` **第四步:** 使用生成的 .lprof 文件运行此命令以查看漂亮的结果:`python -m line_profiler <您的 LPROF 文件>` (2认同)

小智 40

你也可以使用pprofile(pypi).如果要分析整个执行,则不需要修改源代码.您还可以通过两种方式分析较大程序的子集:

  • 到达代码中的特定点时切换分析,例如:

    import pprofile
    profiler = pprofile.Profile()
    with profiler:
        some_code
    # Process profile content: generate a cachegrind file and send it to user.
    
    # You can also write the result to the console:
    profiler.print_stats()
    
    # Or to a file:
    profiler.dump_stats("/tmp/profiler_stats.txt")
    
    Run Code Online (Sandbox Code Playgroud)
  • 通过使用统计分析,从调用堆栈异步切换分析(需要一种在所考虑的应用程序中触发此代码的方法,例如信号处理程序或可用的工作线程):

    import pprofile
    profiler = pprofile.StatisticalProfile()
    statistical_profiler_thread = pprofile.StatisticalThread(
        profiler=profiler,
    )
    with statistical_profiler_thread:
        sleep(n)
    # Likewise, process profile content
    
    Run Code Online (Sandbox Code Playgroud)

代码注释输出格式很像行分析器:

$ pprofile --threads 0 demo/threads.py
Command line: ['demo/threads.py']
Total duration: 1.00573s
File: demo/threads.py
File duration: 1.00168s (99.60%)
Line #|      Hits|         Time| Time per hit|      %|Source code
------+----------+-------------+-------------+-------+-----------
     1|         2|  3.21865e-05|  1.60933e-05|  0.00%|import threading
     2|         1|  5.96046e-06|  5.96046e-06|  0.00%|import time
     3|         0|            0|            0|  0.00%|
     4|         2|   1.5974e-05|  7.98702e-06|  0.00%|def func():
     5|         1|      1.00111|      1.00111| 99.54%|  time.sleep(1)
     6|         0|            0|            0|  0.00%|
     7|         2|  2.00272e-05|  1.00136e-05|  0.00%|def func2():
     8|         1|  1.69277e-05|  1.69277e-05|  0.00%|  pass
     9|         0|            0|            0|  0.00%|
    10|         1|  1.81198e-05|  1.81198e-05|  0.00%|t1 = threading.Thread(target=func)
(call)|         1|  0.000610828|  0.000610828|  0.06%|# /usr/lib/python2.7/threading.py:436 __init__
    11|         1|  1.52588e-05|  1.52588e-05|  0.00%|t2 = threading.Thread(target=func)
(call)|         1|  0.000438929|  0.000438929|  0.04%|# /usr/lib/python2.7/threading.py:436 __init__
    12|         1|  4.79221e-05|  4.79221e-05|  0.00%|t1.start()
(call)|         1|  0.000843048|  0.000843048|  0.08%|# /usr/lib/python2.7/threading.py:485 start
    13|         1|  6.48499e-05|  6.48499e-05|  0.01%|t2.start()
(call)|         1|   0.00115609|   0.00115609|  0.11%|# /usr/lib/python2.7/threading.py:485 start
    14|         1|  0.000205994|  0.000205994|  0.02%|(func(), func2())
(call)|         1|      1.00112|      1.00112| 99.54%|# demo/threads.py:4 func
(call)|         1|  3.09944e-05|  3.09944e-05|  0.00%|# demo/threads.py:7 func2
    15|         1|  7.62939e-05|  7.62939e-05|  0.01%|t1.join()
(call)|         1|  0.000423908|  0.000423908|  0.04%|# /usr/lib/python2.7/threading.py:653 join
    16|         1|  5.26905e-05|  5.26905e-05|  0.01%|t2.join()
(call)|         1|  0.000320196|  0.000320196|  0.03%|# /usr/lib/python2.7/threading.py:653 join
Run Code Online (Sandbox Code Playgroud)

请注意,因为pprofile不依赖于代码修改,所以它可以分析顶级模块语句,允许分析程序启动时间(导入模块所需的时间,初始化全局变量......).

它可以生成cachegrind格式的输出,因此您可以使用kcachegrind轻松浏览大型结果.

披露:我是pprofile作者.

  • 这正是我所寻找的:非侵入性和广泛性. (3认同)

Sat*_*esh 8

为此,您可以借助line_profiler

1. 1st安装包:

    pip install line_profiler
Run Code Online (Sandbox Code Playgroud)

2.使用magic命令将包加载到你的python/notebook环境中

    %load_ext line_profiler
Run Code Online (Sandbox Code Playgroud)

3. 如果要分析函数的代码,
请执行以下操作:

    %lprun -f demo_func demo_func(arg1, arg2)
Run Code Online (Sandbox Code Playgroud)

如果您按照以下步骤操作,您将获得带有所有详细信息的漂亮格式化输出:)

Line #      Hits      Time    Per Hit   % Time  Line Contents
 1                                           def demo_func(a,b):
 2         1        248.0    248.0     64.8      print(a+b)
 3         1         40.0     40.0     10.4      print(a)
 4         1         94.0     94.0     24.5      print(a*b)
 5         1          1.0      1.0      0.3      return a/b
Run Code Online (Sandbox Code Playgroud)


Pe *_*Dro 6

只是为了改进@Joe Kington 的上述答案

对于Python 3.x,使用line_profiler


安装:

pip install line_profiler
Run Code Online (Sandbox Code Playgroud)

用法:

假设您拥有该程序main.py并在其中运行,fun_a()并且fun_b()您想根据时间进行分析;您将需要@profile在函数定义之前使用装饰器。例如,

@profile
def fun_a():
    #do something

@profile
def fun_b():
    #do something more

if __name__ == '__main__':
    fun_a()
    fun_b()
Run Code Online (Sandbox Code Playgroud)

可以通过执行 shell 命令来分析该程序:

$ kernprof -l -v main.py
Run Code Online (Sandbox Code Playgroud)

可以使用获取参数 $ kernprof -h

Usage: kernprof [-s setupfile] [-o output_file_path] scriptfile [arg] ...

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -l, --line-by-line    Use the line-by-line profiler from the line_profiler
                        module instead of Profile. Implies --builtin.
  -b, --builtin         Put 'profile' in the builtins. Use 'profile.enable()'
                        and 'profile.disable()' in your code to turn it on and
                        off, or '@profile' to decorate a single function, or
                        'with profile:' to profile a single section of code.
  -o OUTFILE, --outfile=OUTFILE
                        Save stats to <outfile>
  -s SETUP, --setup=SETUP
                        Code to execute before the code to profile
  -v, --view            View the results of the profile in addition to saving
                        it.
Run Code Online (Sandbox Code Playgroud)

结果将在控制台上打印为:

Total time: 17.6699 s
File: main.py
Function: fun_a at line 5

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    5                                           @profile
    6                                           def fun_a():
...

Run Code Online (Sandbox Code Playgroud)

编辑:可以使用TAMPPA包解析分析器的结果。使用它,我们可以获得逐行所需的图 阴谋