3

我有一个庞大的代码库,现在执行的时间太长了。我不知道是什么。

代码从不引发异常,它只是似乎继续处理某些事情。

我想做的是在一些函数周围放置计时器来测试哪个是罪魁祸首。但我不确定这是否是正确的方法,或者如何去做。

我不能轻易地在代码周围的地方引发异常,因为有各种循环调用相同的函数,有时可能只需要太长时间。

什么是最好的策略?

4

3 回答 3

9

一种解决方案是使用cProfilePython 内置的 . 来判断您的代码在哪些功能上花费的时间最多。至关重要的是,即使您使用 KeyboardInterrupt. 因此,您可以启动代码运行和分析,在一两分钟后停止它,然后查看它在哪里花费时间。

-m使用这些额外和-o参数运行您的代码:

python -m cProfile -o profile.txt myscript.py

然后在程序完成运行后,运行以下代码(例如,从另一个脚本):

import pstats
p = pstats.Stats('profile.txt')
p.strip_dirs().sort_stats("time").print_stats()

这将打印按您在其中花费的总时间排序的功能列表。

这是使用分析来调试无限循环的演示。假设myscript.py有以下代码。

def f():
    while True:
        g(100000)

def g(n):
    x = []
    for i in range(n):
        x.append(n)

f()

当然,这会导致无限循环 - g 将运行很多次。所以我运行上面的分析命令,但在大约 30-40 秒后我停止它(甚至可能更短)。然后其配置文件将打印为:

Wed Jan 30 10:58:50 2013    profile.txt

         115414854 function calls in 37.705 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1155   25.787    0.022   37.020    0.032 test3.py:5(g)
115412541   10.060    0.000   10.060    0.000 {method 'append' of 'list' objects}
     1155    1.173    0.001    1.173    0.001 {range}
        1    0.685    0.685   37.705   37.705 test3.py:1(f)
        1    0.000    0.000   37.705   37.705 test3.py:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

请注意,就函数花费的时间而言,我们的无限循环函数g位于列表的顶部。

注意:仅仅因为代码将所有时间都花在一个函数中并不意味着循环直接围绕该函数 - 它可以由一个函数调用,该函数由无限循环中的函数(等)调用(请注意,append它位于列表顶部附近,因为它被称为 inside g)。另一种技巧是根据在每个函数中花费的累积时间对它们进行排序,使用.sort_stats("cum"). 这两种方法的结合,再加上一点侦探工作(查看代码和添加调试消息),应该能够识别出罪魁祸首。

于 2013-01-30T15:48:56.583 回答
1

我建议使用日志记录模块将调试语句添加到代码中的各个点。使用日志记录模块可以让您轻松打开和关闭调试语句以及控制显示的信息。

另一种选择是使用 IDE,您可以在其中轻松添加断点,从而确定代码进入长循环的位置。

于 2013-01-30T16:00:37.113 回答
1

[编辑:我看到你添加了python-2.7标签,所以这对你没有帮助,但它可能对其他人有用或有趣。]

在 Python 3 中,您可以通过键入Control-C. 然后从调试器中,您可以检查堆栈以查看程序在哪里花费时间。

Python 3.3.0 (default, Nov 23 2012, 10:26:01) 
>>> import time, pdb
>>> def foo(): time.sleep(1); foo()
... 
>>> pdb.run('foo()')
> <string>(1)<module>()
(Pdb) c
^C
Program interrupted. (Use 'cont' to resume).
--Call--
> <stdin>(1)foo()
(Pdb) w
  <stdin>(1)<module>()
  /.../pdb.py(1556)run()
-> Pdb().run(statement, globals, locals)
  /.../bdb.py(405)run()
-> exec(cmd, globals, locals)
  <string>(1)<module>()
  <stdin>(1)foo()
  <stdin>(1)foo()
  <stdin>(1)foo()
  <stdin>(1)foo()
  <stdin>(1)foo()
> <stdin>(1)foo()

您可以将此技术视为一种基于单个样本的基于样本的分析!对于许多问题,您只需要一个样本即可。

于 2013-01-30T16:06:28.873 回答