【问题标题】:Why does completely same function behave differently in ipython/jupyter?为什么完全相同的函数在 ipython/jupyter 中表现不同?
【发布时间】:2021-04-19 19:52:35
【问题描述】:

我有两个相同的函数,例如 sum_nbsum_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


【解决方案1】:

这似乎是缓存行为不一致的结果。 Jupyter 甚至建议这是一个问题:The slowest run took 74.96 times longer than the fastest. This could mean that an intermediate result is being cached.

在我的机器上,具有缓存行为的函数在 ~240ns 内运行,而没有缓存行为的函数在 ~50μs 内运行。

我发现使两个函数之间的行为保持一致的唯一方法是将n=100_000_000 拉入函数体,这使得两个函数都在 ~240ns。

【讨论】:

    猜你喜欢
    • 2019-08-14
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    • 2021-01-27
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多