要理解为什么 Python 代码在函数中运行得更快,我们需要首先了解 Python 是如何执行代码的kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
我们知道,python 是一种解释型语言,它会逐行读取并执行代码kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
当运行一个 python 程序的时候,首先将代码编译成字节码(一种更接近机器码的中间语言)然后 python 解释器执行字节码kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
由上所示,python 中的 dis 模块将函数 hello_world 分解为字节码kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
需要注意的是,python 解释器是一个执行字节码的虚拟机,默认的 python 解释器是用 C 编写的,即 CPythonkcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
还有其他的 python 解释器如 Jython(用 Java 编写),IronPython(用于 )和PyPy(用 Python 和 C 编写)kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
为什么 python 代码在函数中运行得更快
kcy28资讯网——每日最新资讯28at.com
我们来编写一个简单的例子:定义一个函数 my_function,函数内部包含一个 for 循环kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
编译该函数的时候,字节码可能如下所示kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
这里的关键指令是 STORE_FAST ,用于存储循环变量 i kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
现在我们把这个 for 循环放在 python 脚本的顶层(全局范围内),然后再来看一下字节码kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
可以看到关键指令变成了 STORE_NAME,而不是 STORE_FAST kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
字节码 STORE_FAST比 STORE_NAME 快,因为在函数中,局部变量存储在固定长度的数组中,而不是存储在字典中。这个数组可以通过索引直接访问,使得变量检索非常快kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
基本上,它只是一个指向列表的指针,并增加了 PyObject 的引用计数,这两个都是高效的操作kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
另一方面,全局变量存储在一个字典。当访问全局变量时,Python 必须执行哈希表查找,这涉及计算哈希值,然后检索与之关联的值kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
虽然经过优化,但仍然比基于索引的查找慢kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
基准测试验证
kcy28资讯网——每日最新资讯28at.com
我们知道在 Python 中,代码执行的速度取决于代码执行的位置——在函数中还是在全局作用域中kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
让我们用一个简单的基准测试的例子来比较一下kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
首先定义一个求阶乘的函数kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
然后在全局范围内执行相同的代码kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
为了对这两段代码进行基准测试,我们可以在 Python 中使用 timeit 模块,它提供了一种简单的方法来对少量 Python 代码进行计时kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
可以看到,函数代码的执行速度比全局作用域代码要快kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
需要注意的是,这两段代码最好不要放在同一脚本中,要分开单独运行kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
这是因为 benchmark() 函数在执行时间上增加了一些开销,并且全局代码在内部进行了优化kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
cProfile 分析kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
python 提供了一个 cProfile 内置模块kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
让我们用它来分析一个新例子:在局部和全局范围内计算平方和kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
上面的例子中,可以认为sum_of_squares_g() 函数是全局的,因为它使用了两个全局变量, i 和 totalkcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
从性能分析结果中,可以看到函数代码在执行时间方面比全局更有效kcy28资讯网——每日最新资讯28at.com
图片kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
如何优化 python 函数的性能
kcy28资讯网——每日最新资讯28at.com
前面我们知道,Python 代码在函数中运行往往比在全局范围内运行要快得多kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
如果想要进一步提高 python 函数代码效率,不妨考虑一下使用局部变量而不是全局变量kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
另一种方法是尽可能使用内置函数和库。Python 的内置函数是用 C 实现的,比 Python 快得多kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
比如 NumPy 和 Pandas,也是用 C 或 C++ 实现的,它们比实现同样功能的 Python 代码速度更快kcy28资讯网——每日最新资讯28at.com
kcy28资讯网——每日最新资讯28at.com
又比如同样是实现数字求和的功能,python 内置的 sum 函数要比你自己编写函数速度更快kcy28资讯网——每日最新资讯28at.com
本文链接:http://www.28at.com/showinfo-26-10609-0.html为什么 Python 代码在函数中运行得更快?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 使用二进制字面量在现代C++中的应用
下一篇: 数据组合利器:从入门到精通Python中的zip()函数应用