为什么功能较慢?

时间:2015-11-03 20:50:22

标签: python performance python-2.7

我已经构建了一个代码来计算数字的最大素数因子:

import time
start_time = time.time()

num = 600851475143
while num % 2 == 0:
    num /= 2
if num == 1:
    i = 2
else:
    i = 3
    while num > 1:
        if num % i == 0:
            num /= i
        else:
            i += 2
print "%s \n --- %s seconds ---" % (i, time.time() - start_time)

它以0.000769853591919秒运行。 在线搜索我发现了类似但更快的solution。我将这个想法应用到我的代码中,这就是结果:

import time
start_time = time.time()

def lpf(num):
    while num % 2 == 0:
        num /= 2
    if num == 1:
        return 2
    else:
        i = 3
        while num > 1:
            if num % i == 0:
                num /= i
            else:
                i += 2
        return i        

l = lpf(600851475143)

print "%s \n --- %s seconds ---" % (l, time.time() - start_time)

它以0.000453948974609秒运行。 它几乎是前一个的两倍。我不明白逻辑:代码是相同的,但最长的代码运行得更快。为什么?

1 个答案:

答案 0 :(得分:4)

让我们更好地进行测试,每次运行10000次迭代,并从后者中排除函数定义时间(仅计算运行时间):

>>> import timeit
>>> c1='''
... num = 600851475143
... while num % 2 == 0:
...     num /= 2
... if num == 1:
...     i = 2
... else:
...     i = 3
...     while num > 1:
...         if num % i == 0:
...             num /= i
...         else:
...             i += 2
... '''
>>> timeit.timeit(c1, number=10000)
3.5007779598236084

......和替代方案:

>>> c2_setup='''
... def lpf(num):
...     while num % 2 == 0:
...         num /= 2
...     if num == 1:
...         return 2
...     else:
...         i = 3
...         while num > 1:
...             if num % i == 0:
...                 num /= i
...             else:
...                 i += 2
...         return i
... '''
>>> c2_run='l = lpf(600851475143)'
>>> timeit.timeit(setup=c2_setup, stmt=c2_run, number=10000)
3.3825008869171143

...... 较小的差异。

那么,为什么会有任何差异呢?用语言无关的术语来说,更容易优化局部变量的变化;它们不需要写入一个范围,任何其他可能正在运行或未运行的执行线程都可以访问它们。在JITted编译器(如PyPi或JVM)中,对locals的更改实际上可能最终被实现为寄存器修改,而这些修改根本不会转移到CPU外部。

CPython没有JIT支持,但是@chepner给了我们答案:全局变量的读取使用更昂贵的LOAD_GLOBAL指令,而不是本地人可用的LOAD_FAST