为什么第一种方法这么慢?
速度可能会慢1000倍,有关如何加快速度的想法吗?
在这种情况下,性能是第一优先。在我的第一次尝试中,我试图让它成为多种价格,但它也很慢。
Python - Set the first element of a generator - Applied to itertools
import time
import operator as op
from math import factorial
from itertools import combinations
def nCr(n, r):
# https://stackoverflow.com/a/4941932/1167783
r = min(r, n-r)
if r == 0:
return 1
numer = reduce(op.mul, xrange(n, n-r, -1))
denom = reduce(op.mul, xrange(1, r+1))
return numer // denom
def kthCombination(k, l, r):
# https://stackoverflow.com/a/1776884/1167783
if r == 0:
return []
elif len(l) == r:
return l
else:
i = nCr(len(l)-1, r-1)
if k < i:
return l[0:1] + kthCombination(k, l[1:], r-1)
else:
return kthCombination(k-i, l[1:], r)
def iter_manual(n, p):
numbers_list = [i for i in range(n)]
for comb in xrange(factorial(n)/(factorial(p)*factorial(n-p))):
x = kthCombination(comb, numbers_list, p)
# Do something, for example, store those combinations
# For timing i'm going to do something simple
def iter(n, p):
for i in combinations([i for i in range(n)], p):
# Do something, for example, store those combinations
# For timing i'm going to do something simple
x = i
#############################
if __name__ == "__main__":
n = 40
p = 5
print '%s combinations' % (factorial(n)/(factorial(p)*factorial(n-p)))
t0_man = time.time()
iter_manual(n, p)
t1_man = time.time()
total_man = t1_man - t0_man
t0_iter = time.time()
iter(n, p)
t1_iter = time.time()
total_iter = t1_iter - t0_iter
print 'Manual: %s' %total_man
print 'Itertools: %s' %total_iter
print 'ratio: %s' %(total_man/total_iter)
答案 0 :(得分:1)
这里有几个因素在起作用。
最重要的是垃圾收集。由于GC暂停,任何产生大量不必要分配的方法都会变慢。在这种情况下,列表推导是 fast (对于Python),因为它们在分配和执行时被高度优化。在速度很重要的地方,更喜欢列表理解。
接下来你已经有了函数调用。正如@roganjosh在评论中指出的那样,函数调用相对昂贵。如果函数生成大量垃圾或持有长期闭包,那么(再次)尤其如此。
现在我们来到循环。垃圾也是最大的问题,将变量提升到循环之外,并在每次迭代时重复使用它们。
最后但同样重要的是,Python在某种意义上是托管的语言:通常在CPython运行时。在运行时本身实现的任何东西(特别是如果有问题的东西是用C而不是Python本身实现的话)将比你的(逻辑上等价的)代码更快。
所有这些建议都会对代码质量产生不利影响。谨慎使用。首先介绍。另请注意,编译器通常足够聪明,可以为您完成所有这些操作,例如,PyPy通常对于与标准Python运行时相同的代码运行得更快,因为它在运行代码时会对您进行这样的优化。
其中一个实现使用reduce
。从理论上讲,减少可能很快。但这并不是出于很多原因,其中的主要原因可能总结为#34; Guido没有/不关心&#34;。因此,当速度很重要时,请不要使用reduce
。