1

如果我定义了这样的函数:

def ccid_year(seq):
  year, prefix, index, suffix = seq
  return year

是否允许 Python 对其进行有效优化:

def ccid_year(seq):
  return seq[0]

我更喜欢编写第一个函数,因为它记录了传入数据的格式,但希望 Python 生成的代码与第二个定义一样有效。

4

2 回答 2

3

我稍后会从表面上回答这个问题,但首先:如有疑问,请对其进行基准测试!但首先,请回想一下,大部分时间都花在了一小部分代码上(即,大多数代码与性能无关!),在 CPython 中,函数调用开销通常会导致效率低下。更不用说大规模算法效率低下(又名愚蠢的代码)使微优化问题相形见绌。

所以要么根本不用担心这个,或者如果你有理由担心它,第一个基准替代品,第二个不要把它放在一个函数中。请注意,“担心的原因”必须与担心所花费的时间以及手动优化的维护负担(如果有的话)进行权衡。

您最喜欢使用的参考实现 CPython在此级别的优化方面非常保守。虽然有一个窥孔优化器在字节码上运行,但它的规模有限。更一般地说,您不能期望通过单个语句进行很多优化。静态优化 Python 代码的问题在于,即使是看起来最无辜的程序框架也有十亿种方式可以调用任意代码,这可能会做任何事情,所以你不能忽略这些调用。当我们这样做时,您提出的优化是无效的(从某种意义上说,程序没有相同的行为)如果seq是错误的类型(不是序列,或非常奇怪的序列)或长度(不完全是三个项目长)!任何声称实现 Python 的程序都必须保持这种差异,因此它不会按照您的字面意思进行转换。我认为这只是一个临时的说明,但它确实表明您严重低估了 Python 的复杂性(实现和优化)。我和其他人之前已经详细地写过这个,所以我会在这篇文章变得更大之前停下来。

另一方面,如果这个函数确实是从一个热循环中调用的,PyPy 可能会优化这个和一百万个你甚至没有想到的东西,同时将它编译成一个迭代速度比任何 Python 循环都快的机器代码循环可以在 CPython 上进行迭代。它仍将包含一些检查以跳出循环并在必要时采取适当的措施(例如引发异常),但如果不触发它们也将非常有效。

我对 IronPython 和 Jython 以及其他实现了解不多,但如果它们缺乏一致的比 CPython 快几倍的基准测试结果是任何指标,那么它们不会执行显着的优化。虽然 VM IronPython 和 Jython 包含 JIT 编译器(与 PyPy 不同,但不完全不同),但这些 JIT 编译器是为非常不同的语言构建的,如果他们能够查看 IronPython/Jython 的混乱代码,我会感到非常惊讶必须执行以实现 Python 语义并对其执行此类优化。

于 2013-02-14T18:33:37.070 回答
3

这两个功能不等价:

def ccid_year_1(seq):
  year, prefix, index, suffix = seq
  return year

def ccid_year_2(seq):
  return seq[0]

arg = {1:'a', 2:'b', 0:'c', 3:'d'}
print ccid_year_1(arg)
print ccid_year_2(arg)

第一次调用打印0,第二次打印c

于 2013-02-14T18:37:32.927 回答