短路是有代价的。您需要在代码中引入分支。
分支(例如if 语句)的问题在于它们可能比使用替代操作(没有分支)要慢,然后您还有可能包含大量开销的分支预测。
还取决于编译器和处理器,无分支代码可以使用处理器矢量化。我不是这方面的专家,但可能是某种SIMD 或 SSE?
我将在这里使用 numba,因为代码易于阅读且速度足够快,因此性能会根据这些小差异而发生变化:
import numba as nb
import numpy as np
@nb.njit
def any_sc(arr):
for item in arr:
if item:
return True
return False
@nb.njit
def any_not_sc(arr):
res = False
for item in arr:
res |= item
return res
arr = np.zeros(100000, dtype=bool)
assert any_sc(arr) == any_not_sc(arr)
%timeit any_sc(arr)
# 126 µs ± 7.12 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit any_not_sc(arr)
# 15.5 µs ± 962 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit arr.any()
# 31.1 µs ± 184 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
在没有分支的最坏情况下,它几乎快 10 倍。但在最好的情况下,短路功能要快得多:
arr = np.zeros(100000, dtype=bool)
arr[0] = True
%timeit any_sc(arr)
# 1.97 µs ± 12.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit any_not_sc(arr)
# 15.1 µs ± 368 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit arr.any()
# 31.2 µs ± 2.23 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
所以这是一个应该优化哪种情况的问题:最好的情况?最坏的情况?平均情况(any 的平均情况是多少)?
这可能是 NumPy 开发人员想要优化最坏情况而不是最佳情况。还是他们根本不在乎?或者,也许他们只是想要“可预测”的性能。
请注意您的代码:您测量创建数组所需的时间以及执行any 所需的时间。如果any 发生短路,您的代码就不会注意到它!
%timeit np.ones(10**6)
# 9.12 ms ± 635 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit np.ones(10**7)
# 86.2 ms ± 5.15 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
对于支持您的问题的决定性时间,您应该改用这个:
arr1 = np.ones(10**6)
arr2 = np.ones(10**7)
%timeit arr1.any()
# 4.04 ms ± 121 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit arr2.any()
# 39.8 ms ± 1.34 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)