当我将“%timeit”放入带有 IPython/Jupyter 的函数中时,为什么会得到错误的计时结果?

Why do I get bad timing results when I put "%timeit" inside a function with IPython/Jupyter?

我正在学习如何在 IPython 中使用 %timeit 魔术命令,实际上是在 Python 中使用 Jupyter notebook 3. 如果我尝试为各种大小的 NumPy 排序函数计时数组:

n = 10
for i in range(n):
    arr = np.random.rand(2**(i+10))
    %timeit -n 2 np.sort(arr)

然后我得到了一系列大致递增的时间,正如我所期望的那样。

如果我尝试将此代码打包到一个函数中,但是,我没有得到我期望的输出:所有时间都差不多!

def my_func(n):
    for i in range(n):
        arr = np.random.rand(2**(i+10))
        %timeit -n 10 np.sort(arr)
my_func(10)

请查看显示结果的 Jupyter notebook here

谁能解释我做错了什么,或者我误解了什么?

%timeit 不应该在函数内部正确 工作(目前)。如果你开始一个新的笔记本(或重新启动你的)并且只使用:

import numpy as np
def my_func(n):
    for i in range(n):
        arr = np.random.rand(2**(i+10))
        %timeit -n 10 np.sort(arr)

my_func(10)

它会抛出一个 NameError:

NameError: name 'arr' is not defined

那是因为 %timeit 只检查全局变量而不检查局部变量(因此它忽略了函数中定义的变量 arr = np.random.rand(2**(i+10)))。

如果你使用这段代码就会很明显:​​

import numpy as np

arr = np.array([1, 2, 3])

def my_func(n):
    for i in range(n):
        arr = np.random.rand(2**(i+10))
        %timeit -n 2 -r 1 print(arr)

my_func(10)

打印:

[1 2 3]
[1 2 3]
3.44 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
670 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
2.04 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
451 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
906 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
1.01 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
767 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
890 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
1.28 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
[1 2 3]
[1 2 3]
919 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)

所以在你的情况下,它总是从你的非函数运行(这是全局的)中找到最后一个 arr。这也解释了为什么函数的时间大致相同。因为它总能找到相同的arr.