如何加速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%)。。