我试图制作一个纯Python(不依赖外部库)的逐元素比较两个序列的函数。我的第一个解决方案是:
list(map(operator.eq, seq1, seq2))
后来我发现itertools
库中有一个starmap
函数,它看起来与之前的函数相似。但最终结果表明,在我的计算机上,它在最坏情况下比之前的函数快了37%。因为这对我来说不是显而易见的,所以我使用了一种方法来测量从生成器中检索1个元素所需的时间(不知道这种方法是否正确):
from operator import eq
from itertools import starmap
seq1 = [1,2,3]*10000
seq2 = [1,2,3]*10000
seq2[-1] = 5
gen1 = map(eq, seq1, seq2))
gen2 = starmap(eq, zip(seq1, seq2))
%timeit -n1000 -r10 next(gen1)
%timeit -n1000 -r10 next(gen2)
271 ns ± 1.26 ns per loop (mean ± std. dev. of 10 runs, 1000 loops each)
208 ns ± 1.72 ns per loop (mean ± std. dev. of 10 runs, 1000 loops each)
在检索元素方面,第二种解决方案的性能提高了24%。之后,它们都会为list
产生相同的结果。但是我们从某个地方获得了额外的13%时间:
%timeit list(map(eq, seq1, seq2))
%timeit list(starmap(eq, zip(seq1, seq2)))
5.24 ms ± 29.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.34 ms ± 84.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
我不知道如何深入剖析这样嵌套的代码?所以我的问题是,为什么第一个生成器在检索时速度更快,并且我们从何处获得了list
函数额外的13%?
编辑:
我的第一个意图是执行逐元素比较而不是all
,因此all
函数被替换为list
。这个替换不会影响时间比。
CPython 3.6.2 在 Windows 10 (64位) 上运行。
seq1 == seq2
? - Błotosmętekall
,这从我的问题中并不明显 :) 实际上,如果您将all
替换为list
,时间顺序将保持不变。 - godaygo