【发布时间】:2021-04-19 19:52:35
【问题描述】:
我有两个相同的函数,例如 sum_nb 和 sum_nb2。我用@njit装饰器定义它们:
from numba import njit
from timeit import timeit
@njit
def sum_nb(n=100_000_000):
s = 0
for i in range(n):
s += i
return s
@njit
def sum_nb2(n=100_000_000):
s = 0
for i in range(n):
s += i
return s
如果我只是保存为脚本并添加代码来测量执行时间,一切都会很好:
print(sum_nb())
print(sum_nb2())
print(timeit(sum_nb))
print(timeit(sum_nb2))
输出是:
4999999950000000
4999999950000000
0.41249959499691613
0.4120563520118594
现在我打开 ipython 控制台/jupyter 实验室并将第一个代码复制到单元格。然后我用魔法测量单元格中的代码时间:
In [3]: %timeit sum_nb()
240 ns ± 86.5 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [4]: %timeit sum_nb2()
7.32 µs ± 90 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
在 jupyter 实验室中也会发生同样的情况。它是如何发生的?这个怎么运作?为什么相同的代码有不同的速度?
我有 ipython 7.7.0、numba 0.44.1、python 3.7.3、jupyter lab 1.0.2
【问题讨论】:
-
如果我不得不猜测的话,JIT 编译器可能很奇怪
-
似乎已经决定运行 sum_nb() 进行更多循环。也许这在拥有更热的缓存或更好的分支预测方面有所不同?可能最小化 JIT 开销?手动强制执行相同数量的循环并运行,然后重试。
-
浮点数学不应该是不稳定的吗?
-
@Gus 并不是我决定了什么。我只是让 %magic 自己决定运行代码的次数。但是,如果我运行
timeit(sum_nb, number=10_000_000)和sum_nb2相同,我会分别得到 3.1 和 99.3 的结果。 -
我可以确认您看到的结果。请注意,只有
return (n + 1) * n // 2的函数运行速度与更快的结果差不多(实际上快一点),所以我倾向于假设 Numba(或 LLVM)在幕后使用这种优化以获得更快的结果,并执行用于较慢结果的“标准”循环。
标签: python ipython jupyter numba