首页 > 解决方案 > 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%)。

标签: pythonoptimizationgenerator

解决方案


推荐阅读