Python 函数调用性能记录

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 函数调用性能记录相关的知识,希望对你有一定的参考价值。

之前用 JS 写项目的时候,项目组用的组件模式,一直感觉很不错。最近用 Python 做新项目,项目结构也延续了组件模式。一直没有对函数调用的性能作了解,今天突发奇想测试了一下,写了一些测试代码

 

首先定义了几个 class :

class A(object):
    def test(self):
        pass

class B(object):
    def __init__(self):
        self.a = A()

    def test(self):
        pass

class C(object):
    def __init__(self):
        self.b = B()

    def test(self):
        pass

class D(object):
    def __init__(self):
        self.c = C()
    def test(self):
        pass

 

对比1:

直接调用实例对象身上的方法 和 使用变量缓存该方法然后调用

n = 10000000
import timeit

a = A()
t_direct = timeit.Timer(a.test(), from __main__ import a).timeit(n)
print direct call func : , t_direct

cache = a.test
t_cache = timeit.Timer(cache(), from __main__ import cache).timeit(n)
print cache func call  : , t_cache

print  performance : , (t_cache / t_direct)

 

尝试多次后得出该情况下的时间结论:

direct call func :  1.14136314392
cache func call  :  0.745277881622
 performance :  0.652971743123

缓存方法之后再调用,性能大约能提升 35%

调用函数时,python 会临时创建一个对象,比如直接调用函数 a.test() 时,python 会执行如下步骤:

1: temp = a.test

2: temp()

3: del temp

所以频繁调用时,性能上是一个问题。内存上应该也是一个问题,感觉会更加频繁的触发 gc

 

对比2:

通过成员变量多层调用一个函数,和直接调用对象身上的函数的性能差

t0 = timeit.Timer(d.test(), from __main__ import d).timeit(n)
print 0 level:  , t0

t1 = timeit.Timer(d.c.test(), from __main__ import d).timeit(n)
print 1 level:  , t1,     : , (t1 / t0) * 100

t2 = timeit.Timer(d.c.b.test(), from __main__ import d).timeit(n)
print 2 level:  , t2,     : , (t2 / t1) * 100,     , (t2 / t0 * 100)

t3 = timeit.Timer(d.c.b.a.test(), from __main__ import d).timeit(n)
print 3 level:  , t3,     : , (t3 / t2) * 100,     , (t3 / t0 * 100)

 

尝试多次后得出该情况下的时间结论:

0 level:   1.26769399643

1 level:   1.50338602066     :  118.592185882

2 level:   1.74297595024     :  115.936687337      137.491851752

3 level:   1.87865877151     :  107.784549251      148.194972667

基本上,函数调用层次多一层,性能消耗会多 5% 到 15% 左右

这个暂时无法详细的解答。手上也没有 JS 的测试数据,不确定当时 js 些写项目的时候,是否也存在这个性能问题。

 

之前碰到一些项目的结构是,写的时候分成了多个文件来写,但是最后运行的时候,会把这多个文件中定义的 属性、函数都聚合到一个 class 身上,成为一个巨无霸级的 class。一直不理解这么做的意义是什么,感觉很臃肿,现在看来 估计为了减少函数调用的层次,提高性能。

 

以上是关于Python 函数调用性能记录的主要内容,如果未能解决你的问题,请参考以下文章

python使用上下文对代码片段进行计时,非装饰器

[转]perf + 火焰图分析程序性能

Python 函数声明和调用

Python函数

性能有瓶颈?3 个实时可视化 Python 工具包来帮你!

在 Python 多处理进程中运行较慢的 OpenCV 代码片段