传入变量的效率与为多次调用的函数重新定义它们的效率

Efficiency of passing in variables versus redefining them for a function called many times

我有一个关于效率的问题,我对处理速度和内存效率都很感兴趣。

我正在编写多次调用函数的代码。在它的参数中,有些需要保留变量,因为每次调用函数时这些参数的值都不同。然而,其他的是不变的,不仅每次调用函数时都相同,而且每次代码为 运行 时也不改变,甚至在 运行 之间也不改变。但是,我还是想把它们写成变量而不是硬编码,这样我就可以通过描述性的名称来引用它们。

在下面的示例中,我希望前两个同样有效,而最后一个效率不高。但是,我不清楚为什么。谁能帮忙解释一下?

编辑:在下面的示例中,我只使用了 100 次迭代。实际上,我希望以这种方式调用函数数千或数百万次。

编辑 2:对于那些只是告诉我对其进行概要分析的人。请注意,我问的是 why,而不仅仅是 if,有些方法比其他方法更有效。分析会回答如果但不是为什么。

import numpy as np

def myfunc(a):
    (a**4) + np.sqrt(3)*a - a/3

for a in arange(100):
    y[a] = myfunc(a)

对比

import numpy as np
myb = 3

def myfunc(a):
    (a**4) + np.sqrt(myb)*a - a/myb

for a in arange(100):
    y[a] = myfunc(a)

对比

import numpy as np
myb = 3

def myfunc(a, b):
    (a**4) + np.sqrt(b)*a - a/b

for a in arange(100):
    y[a] = myfunc(a, myb)

您所说的效率水平并不重要。您应该担心代码的可读性,而不是移动一些值的效率。如果每次通过循环将值传递给函数的代码更具可读性,即使它们没有改变,也将它们传递给函数。例如,就理解代码的作用而言,将内容放在全局变量中通常可读性要差得多。

这是我拼凑的一个例子:

import random

def foo(iter, a, b, c, d, e, f, g, h, i ,j):
    x = a + b + c + d + e + f + g + h + i + j
    if iter % 100000 == 0:
        print(x)

for i in range(1000000):
    foo(i, random.random() * 100,
        random.random() * 100,
        random.random() * 100,
        random.random() * 100,
        random.random() * 100,
        random.random() * 100,
        random.random() * 100,
        random.random() * 100,
        random.random() * 100,
        random.random() * 100)

结果:

658.9874644541911
643.4372986147371
636.6218502753122
475.3660640474451
648.4789890659888
466.2721794578193
595.3755252194462
583.45879143973
498.04278700281304
283.2047039562956

此代码执行一百万次迭代,创建 10 个随机值,将每个随机值乘以 100,将它们分别传递给函数,然后在函数中对它们求和。每 100,000 次迭代,我打印总和值作为完整性检查。

这在我的 Macbook Pro 上运行 2-3 秒。我们现在的计算机真的非常快而且功能强大。如此之多以至于几乎不值得担心您正在谈论的优化类型。

更新:为了更进一步,因为我很好奇,我尝试取出随机数生成,所以 运行 这个:

for i in range(1000000):
    foo(i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

这个基本是瞬时运行,一眨眼就打印十次55。所以第一个例子大部分是10M随机数的生成。我会进一步指出,由于涉及这些常量,编译器和处理器可能都在优化 wazoo,因为在这种情况下没有任何变化。但这只会进一步推动这一点。没有理由担心传递常量值,部分原因是如今的编译器和处理器会为您识别并优化此类模式。避免这些优化是我在第一个示例中使用 random() 的原因。

内存是一个不同的问题,但通常是由问题本身决定的,而不是你如何做的。在某些情况下,当内存成为一个特定问题时,您需要变得聪明(批量处理、使用流处理等)。记忆问题是在哪里知道我们正在谈论的数字种类以及数据的一般情况会很好。