python - Python:加速函数调用
问题描述
如何加快 python 函数调用。我知道我可以使用 pypy 来加快它的速度,但我想看看我可以通过坚持使用常规的 python 解释器来获得多快。
为每个任务创建函数可以使代码更清晰、更易于阅读,但似乎会大大降低代码速度,尤其是在这些函数被调用数百万次的情况下。
下面举一个简单的例子。当然实际上这些函数更复杂,但我只是为每个函数使用了一个简单的函数,只是为了显示函数调用可能有多少额外的开销。第一个例子使用函数,其中get_type
调用5000万次, do_even
调用2500万次,do_odd
调用2500万次。第二个例子去掉了所有这些函数调用,直接放置了逻辑。这个例子看起来不错,但是对于逻辑更复杂并且代码干净的现实生活例子,这可能无法实现。第三个例子使用了生成器,它比使用函数快一点,但不如不使用函数快。
import datetime
TOTAL = 50000000
def timer(func):
def wrapper(*args, **kwargs):
start = datetime.datetime.now()
res = func(*args, **kwargs)
print("{} took: {}".format(func.__name__, datetime.datetime.now() - start))
return res
return wrapper
def get_type(num):
if num%2:
return "even"
else:
return "odd"
def do_even(counter):
counter["even"] += 1
def do_odd(counter):
counter["odd"] += 1
@timer
def with_functions():
counter = {"even": 0, "odd": 0}
for num in range(TOTAL):
type = get_type(num)
if type == "even":
do_even(counter)
else:
do_odd(counter)
@timer
def no_functions():
counter = {"even": 0, "odd": 0}
type = None
for num in range(TOTAL):
if num % 2:
type = "even"
else:
type = "odd"
if type == "even":
counter["even"] += 1
else:
counter["odd"] += 1
def g_evens(counter):
while 1:
counter["even"] += 1
yield
def g_odds(counter):
while 1:
counter["odd"] += 1
yield
@timer
def generators():
counter = {"even": 0, "odd": 0}
g_even = g_evens(counter)
g_odd = g_odds(counter)
for num in range(TOTAL):
if num % 2:
next(g_even)
else:
next(g_odd)
with_functions()
no_functions()
generators()
python 3(linux)中的输出:
with_functions took: 0:00:18.344544
no_functions took: 0:00:09.707193
generators took: 0:00:12.016994
pypy3(linux)中的输出:
with_functions took: 0:00:01.562282
no_functions took: 0:00:01.513855
generators took: 0:00:02.496888
在pypy3中,有函数和无函数似乎没有太大区别。有没有办法在常规的 python 解释器中做到这一点?或者我真的不应该担心它,因为实际上更复杂的逻辑可能需要更长的时间,额外的 9 秒真的没什么。但是在这里,由于示例非常简单快捷,因此 9 秒似乎占总执行时间的很多(~50%)。
解决方案
推荐阅读
- bootstrap-4 - Bootstrap 4.1 - 模式因“错误:Object.keys:参数不是对象”而失败
- android - 带有两个的 FrameLayout 仅包括正确设置第一个。为什么?
- batch-file - 批量打开网页并在 10 秒后截图
- c# - 如何将模型的实例添加到列表中
- asp.net-mvc - 为什么路由器总是使用路由参数的默认值,而不是提供的?
- javascript - 使用 Javascript 检索 TD 锚点的 html 表格内容
- .net - 使用 ajax 和 .NET Web 应用程序跨域
- c++ - 使用 SendMessage() 的鼠标单击未移交给窗口
- linux - 在 glibc 的 malloc 中使用 POSIX 信号量
- jquery - jQuery 和 Giphy - 下载后设置背景图像