Python 性能分析 - runsnakerun 输出中的列是什么意思?

8 投票
2 回答
1386 浏览
提问于 2025-04-18 05:05

这可能很明显,但我想确认一下我对runsnakerun中的各个列的理解。

名称、调用次数、递归调用次数、本地、每次调用、累计、每次调用、文件、行、目录

以下是我认为我理解的一些内容:

名称 - 被调用的函数名称

  1. 调用次数 - 是指调用的次数吗?
  2. 文件 - 存放这个函数的文件
  3. 行 - 函数在文件中的定义行
  4. 目录 - 存放函数定义的文件所在的目录

我不太确定的其他几个是:

  1. 递归调用次数
  2. 本地
  3. 每次调用
  4. 累计
  5. 每次调用

谢谢

2 个回答

7

这是我对这些内容的理解:

  • RCalls 表示递归调用的次数
  • Local 表示在本地执行上花费的总时间(没有调用其他方法)
  • /Call 表示每次调用的本地时间
  • Cum 表示总的累积时间
  • /Call 表示每次调用的累积时间
6

最好的方式是通过一个例子来说明——假设你有一个程序(存储在profileme.py中,为了清晰起见,分成了几部分):

def topfunction():
    tinyfunction()
    for i in range(100000):
        manytinyfunction()

Calls很简单——就是这个函数被直接调用了多少次。当然,当你选择左侧的项目时,这些数字会变化,反映出被选中的函数调用了这个函数多少次。比如,manytinyfunction会被调用100,000次,所以calls就是100,000。而tinyfunction只会被调用一次,所以它的calls就是1。

    for i in range(10):
        recursive(100)

rcalls和calls类似,但它还包括在执行一个调用时发生的其他调用。注意recursive的calls只有10,但rcalls是1010(下面会解释,它会自己调用n次,如果它的参数是n)。

    alllocal()
    allcumulative()

同样,local包括在函数内部花费的所有时间,不算调用其他函数的时间。在这里,alllocal的值很大,但allcumulative没有值,因为它把工作转给了subfunction

def tinyfunction():
    pass

def manytinyfunction():
    pass

/Call next to the local只是把上面的local值按调用次数分解,所以manytinyfunction整体花费的时间很少,但在local /call中是一个非常非常小的数字,因为每次调用的成本真的很低。

def alllocal():
    for i in range(1000):
        for j in range(1000):
            for k in range(1000):
                pass

对于alllocal,/call的值会很大,无论是local还是cumulative,因为这个函数的开销很大,而所有的开销都是local的。

def allcumulative():
    for i in range(1000):
        subfunction()

def subfunction():
    for j in range(1000):
        for k in range(1000):
            pass

/Call next to cumulative和local的/call是一样的,只不过它像cumulative本身一样,包含了从这个函数调用出去的所有调用的完整成本。所以allcumulative的local /call数字很小,但alllocal的数字很大。而cumulative /call在这两种情况下是一样的。

def recursive(n):
    if n > 0:
        return recursive(n-1)
    else:
        return 0

这里提供了recursive的定义以供参考。

if __name__=="__main__":
    topfunction()

在对其进行性能分析并运行runsnake后:

python -m cProfile -o profileme.out profileme.py 
runsnake profileme.out

注意到alllocal在local和cumulative上都有很大的值,而allcumulative则明显不同。注意recursive在两列中是一样的——对自己调用的次数是被计算在内的。

底部的Callees按钮可以让你找出被选中的函数调用了哪些其他函数,而Callers则可以让你找出是谁在调用这个选中的函数。

撰写回答