我最近回答了一个question on a sister site,它要求一个对一个数字的所有偶数位数进行计数的函数。其中一个other answers包含两个函数(到目前为止,这是最快的):
def count_even_digits_spyr03_for(n):
count = 0
for c in str(n):
if c in "02468":
count += 1
return count
def count_even_digits_spyr03_sum(n):
return sum(c in "02468" for c in str(n))
此外,我还研究了使用列表理解和list.count
:
前两个函数本质上是相同的,只是第一个函数使用显式计数循环,而第二个函数使用内置的sum
。我本以为第二个会更快(基于例如this answer),如果要求复查的话,我会建议把前者变成这样。但是,事实恰恰相反。用一些位数不断增加的随机数进行测试(因此任何一个数字为偶数的概率约为50%),我得到以下计时:
{sum
快一倍。由于内置的sum
应该比手动求和列表快5倍(根据the linked answer),这意味着它实际上要快十倍!只需为一半的值添加一个值,而另一半被丢弃,这是否足以解释这种差异?在
使用if
作为过滤器,如下所示:
def count_even_digits_spyr03_sum2(n):
return sum(1 for c in str(n) if c in "02468")
只将计时改进到与列表理解相同的级别。在
当将计时扩展到更大的数字,并规范化为for
循环计时时,它们会渐进地收敛到非常大的数字(>10k位),这可能是由于str(n)
所花费的时间:
如果我们使用
dis.dis()
,我们可以看到函数的实际行为。在count_even_digits_spyr03_for()
:我们可以看到只有一个函数调用,在开头是对
^{pr2}$str()
:其余部分是高度优化的代码,使用跳转、存储和就地添加。在
什么是
count_even_digits_spyr03_sum()
:虽然我不能完美地解释这些差异,但是我们可以清楚地看到有更多的函数调用(可能是}(?),这使得代码的运行速度比直接执行机器指令慢得多。在
sum()
和{@MarkusMeskanen的答案是正确的-函数调用很慢,genexpr和listcomp基本上都是函数调用。在
总之,要务实:
使用} in Python 可以使事情更快。在
str.count(c)
更快,this related answer of mine about ^{结果:
^{pr2}$sum
相当快,但{sum
使用其整数快速路径。在与列表理解相比,生成器有两个主要优点:它们占用更少的内存;如果不需要所有元素,它们可以提前终止。它们的设计目的是在需要所有元素的情况下提供时间优势。每个元素暂停和恢复一个生成器非常昂贵。在
如果我们用列表理解代替genexp:
我们看到了一个立即加速,代价是在一个列表上浪费大量内存。在
如果你看看你的genexp版本:
^{pr2}$你会发现它没有
if
。它只会将布尔值放入sum
。相反,你的循环:只有在数字为偶数时才添加任何内容。在
如果我们将前面定义的
f2
更改为同时包含一个if
,我们会看到另一个加速:f1
,与您的原始代码相同,耗时52.2µs,f2
,只需修改列表理解,就需要40.5µs使用
True
而不是f3
中的1
可能看起来相当尴尬。这是因为将其更改为1
会激活最后一个加速。sum
对整数有一个fast path,但是快速路径只对类型正好是int
的对象激活。bool
不计算。这是检查项目是否属于int
类型的行:完成最后的更改后,将
True
更改为1
:我们看到最后一个小的加速。在
那么在所有这些之后,我们是否打破了显式循环?在
没有。我们基本上已经收支平衡,但我们还没赢。剩下的最大问题是名单。构建它非常昂贵,
sum
必须通过列表迭代器来检索元素,这有其自身的成本(尽管我认为这部分相当便宜)。不幸的是,只要我们使用测试数字和call-sum
方法,就没有任何好的方法来删除列表。显式循环获胜。在我们能再进一步吗?到目前为止,我们一直在努力使}:
sum
更接近显式循环,但是如果我们坚持这个愚蠢的列表,我们可以脱离显式循环,只调用len
而不是{单独测试数字并不是我们可以尝试打破循环的唯一方法。进一步偏离显式循环,我们还可以尝试
str.count
。str.count
直接在C语言中遍历字符串的缓冲区,避免了很多包装对象和间接寻址。我们需要调用它5次,在字符串上传递5次,但它仍然有回报:不幸的是,这是我用来计时的网站因为使用了太多的资源而被困在“tarpit”中,所以我不得不切换站点。以下时间不能与上述时间直接比较:
相关问题 更多 >
编程相关推荐