加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – 函数调用执行速度比非函数调用快

发布时间:2020-12-20 12:13:40 所属栏目:Python 来源:网络整理
导读:函数调用总会产生一些开销.但为什么下面的代码显示非函数调用较慢. 码: import timedef s(): for i in range(1000000000): 1 + 1t = time.time()s()print("Function call: " + str(time.time() - t))t = time.time()for i in range(1000000000): 1 + 1print
函数调用总会产生一些开销.但为什么下面的代码显示非函数调用较慢.

码:

import time

def s():
    for i in range(1000000000):
        1 + 1

t = time.time()
s()
print("Function call: " + str(time.time() - t))

t = time.time()
for i in range(1000000000):
    1 + 1
print("Non function call: " + str(time.time() - t))

输出:

Function call: 38.39736223220825
Non function call: 60.33238506317139

解决方法

您可能会认为,由于循环仅执行1 1,因此应该没有太大区别.但是,这里有一个“隐藏的” assignment通常被遗忘:你的for循环中的循环变量i.这是经济放缓的原因.

在函数中,这是通过STORE_FAST完成的.在顶层,它是用STORE_NAME完成的.第一个比另一个快,并且在一个运行1000000000次的循环中,这个差异非常清楚地显示出来.

请记住,函数调用只发生一次.因此,它的开销在这种特定情况下并没有真正贡献.

除此之外,所有其他步骤只发生一次并且几乎相同.创建一个范围并抓取其迭代器,并为每次迭代加载常量2.

您始终可以使用dis module来检查为每个生成的CPython字节码,如@Moses在注释中指示的那样.对于函数s,您有:

dis.dis(s)
#       snipped for brevity
        >>   10 FOR_ITER                 8 (to 20)
             12 STORE_FAST               0 (i)

  3          14 LOAD_CONST               3 (2)
             16 POP_TOP
             18 JUMP_ABSOLUTE           10

而对于循环的顶级版本:

dis('for i in range(1000000000): 1+1')
#       snipped for brevity
        >>   10 FOR_ITER                 8 (to 20)
             12 STORE_NAME               1 (i)
             14 LOAD_CONST               3 (2)
             16 POP_TOP
             18 JUMP_ABSOLUTE           10

这些之间的主要区别在于存储迭代值i.在功能方面,它更有效率.

为了解决@Reblochon Masque(现已删除)的答案,这似乎表明在IPython单元格中与timeit计时时这两者之间没有差异.

timeit通过创建一个小函数(named inner)来计算事物,该函数存储您传递的语句并在给定次数的执行中执行它们.你可以看到这个,如果你创建一个Timer对象并查看它的src属性(这没有记录,所以不要指望它总是在那里:-):

from timeit import Timer

t = Timer('for i in range(10000): 1 + 1')
print(t.src)

这包含基本上定时的小功能.之前的打印调用打印:

def inner(_it,_timer):
    pass
    _t0 = _timer()
    for _i in _it:
        for i in range(10000): 1 + 1
    _t1 = _timer()
    return _t1 - _t0

因此,实际上,通过使用timeit,您已经改变了执行i查找的方式,因为它在函数内部,也是使用STORE_FAST完成的.容易陷入困境!

(如果你不相信我,请参阅dis.dis(compile(t.src,”,’exec’).co_consts [0]))

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读