【发布时间】:2019-09-21 21:36:34
【问题描述】:
这里我有两个功能:
from functools import reduce
from operator import mul
def fn1(arr):
product = 1
for number in arr:
product *= number
return [product//x for x in arr]
def fn2(arr):
product = reduce(mul, arr)
return [product//x for x in arr]
基准测试:
In [2]: arr = list(range(1,11))
In [3]: %timeit fn1(arr)
1.62 µs ± 23.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [4]: %timeit fn2(arr)
1.88 µs ± 28.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [5]: arr = list(range(1,101))
In [6]: %timeit fn1(arr)
38.5 µs ± 190 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [7]: %timeit fn2(arr)
41 µs ± 463 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [8]: arr = list(range(1,1001))
In [9]: %timeit fn1(arr)
4.23 ms ± 25.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [10]: %timeit fn2(arr)
4.24 ms ± 36.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [11]: arr = list(range(1,10001))
In [12]: %timeit fn1(arr)
605 ms ± 4.97 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [13]: %timeit fn2(arr)
594 ms ± 4.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
这里fn2() 的小列表稍微慢一些。我的理解是reduce() 和mul() 函数都是内置函数,因此它们以C 的速度运行并且应该比for 循环更快。可能是因为我在fn2 中有更多的函数调用(这也需要一些时间),它有助于最终性能?但随后趋势表明,fn2() 的性能优于fn1() 的列表更大。为什么?
【问题讨论】:
-
这些都是非常接近的时间度量,我认为一种或另一种方法之间确实没有显着差异。
reduce以防万一您更喜欢功能性更强的编程方式,它不应该是一种优化。此外,您在函数中有一个列表理解,无论如何可能要花费大部分时间,特别是考虑到您正在用数以千计的数字除数(10,000!需要超过 100,000 位来存储)。 -
推测这些微小的差异可能是由额外的调用引起的——for循环和算术操作可能比调用
mul的开销要快一点。 (似乎标准的 CPython 解释器不做内联。stackoverflow.com/questions/6442050/…,请注意 PyPy 如何因其内联支持而得到特别提及)。你不应该太担心这个;如果这种规模的性能很重要,那么 Python 可能是一个错误的工具。 (虽然你可以试试 PyPy。) -
是的,但是为什么趋势是这样的呢?如果
for循环 + 算术运算 (fn1) 的计算时间比reduce()+mul()(mul()(fn2) 少,那么无论列表大小如何,它都应该保持正确,对吧?此外,列表中的项目越多,fn1和fn2之间的计算距离就会增加,因为函数调用越多,它就需要更多的时间。但我观察到相反的情况,似乎列表中的项目越多fn2神奇地开始表现得比fn1更好。
标签: python python-3.x