我已经构建了一个代码来计算数字的最大素数因子:
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秒运行。 它几乎是前一个的两倍。我不明白逻辑:代码是相同的,但最长的代码运行得更快。为什么?
答案 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
。