Python是否优化循环中的函数调用?

Python是否优化循环中的函数调用?,python,optimization,compiler-optimization,Python,Optimization,Compiler Optimization,比如说,我有一个代码,它从循环中调用某个函数数百万次,我希望代码速度更快: def outer_function(file): for line in file: inner_function(line) def inner_function(line): # do something pass 它不一定是一个文件处理,例如,它可以是从函数绘制线调用的函数绘制点。从逻辑上讲,这两者必须分开,但从性能的角度来看,它们应该尽可能快地协同工作 Python会

比如说,我有一个代码,它从循环中调用某个函数数百万次,我希望代码速度更快:

def outer_function(file):
    for line in file:
        inner_function(line)

def inner_function(line):
    # do something
    pass
它不一定是一个文件处理,例如,它可以是从函数绘制线调用的函数绘制点。从逻辑上讲,这两者必须分开,但从性能的角度来看,它们应该尽可能快地协同工作


Python会自动检测并优化这些东西吗?如果没有-有没有办法给它一个这样做的线索?使用一些额外的外部优化器?..

调用函数来调用
pass
语句显然会带来相当高的成本(∞) 开销。你的实际程序是否受到不必要的开销取决于内部函数的大小。如果它真的只是设置一个像素,那么我建议使用一种不同的方法,使用以C语言或C++语言编写的绘图原语。 有一些(有些实验性的)Python JIT编译器可以优化函数调用,但主流Python不会这样做。

如果你所说的“Python”是指普遍使用的实现,则不是


如果使用“Python”你说的是Python语言的任何实现,是的。可以进行很多优化,我相信它的方法JIT应该能够处理类似的情况。

Python不内联函数调用,因为它是动态的。理论上,
内部函数
可以将名称
内部函数
重新绑定到something else-Python无法在编译时知道可能发生这种情况。例如:

def func1():
    global inner_func
    inner_func = func2
    print 1

def func2():
    print 2

inner_func = func1

for i in range(5):
    inner_func()
印刷品:

1
2
2
2
2
你可能认为这很可怕。然后,再想想——Python的功能性和动态性是它最吸引人的特性之一。Python允许的很多东西都是以性能为代价的,在大多数情况下这是可以接受的

也就是说,你可能可以使用类似的工具将一些东西组合在一起——将内部函数分解成字节码,插入外部函数,然后重新组装。再想一想,如果你的代码对性能要求很高,足以进行此类攻击,只需用C语言重写即可。Python对FFI有很好的选择


这一切都与官方的CPython实现有关。一个运行时JITting解释器(比如PyPy或不幸倒闭的unladenswallow)理论上可以检测正常情况并执行内联。唉,我对PyPy不太熟悉,不知道它是否能做到这一点,但它肯定能做到。

哪种Python?PyPy的JIT编译器会在几百或几十次之后(取决于每次迭代执行多少操作码)迭代——开始跟踪执行,一路上忘记Python函数调用,将收集的信息编译成一段优化的机器代码,这段代码可能没有导致函数调用本身发生的任何逻辑残余。跟踪是线性的,JIT的后端甚至不知道有函数调用,它说只看到来自两个函数的指令在执行时混合在一起。(这是一个完美的例子,例如循环中存在分支或所有迭代都采用相同的分支。有些代码不适合这种JIT编译,并在它们产生很大加速之前使跟踪快速失效,尽管这是相当罕见的。)

现在,CPython,许多人在谈论“Python”时是什么意思或者Python解释器,它不是很聪明。它是一个直截了当的字节码VM,它将尽责地执行在每次迭代中一次又一次调用函数的逻辑。但是,如果性能是<强> > <强>重要的话,为什么还要使用解释器?考虑在原生代码中编写热循环。(例如,作为C扩展或in)如果保持尽可能低的开销非常重要

除非每次迭代只进行一点点的数字运算,否则无论如何都不会有很大的改进。

CPython(“标准”python实现)不会进行这种优化

但是请注意,如果您正在计算函数调用的CPU周期,那么对于您的问题,CPython可能不是正确的工具。如果您100%确定您将要使用的算法已经是最好的(这是最重要的事情),并且您的计算确实是CPU受限的,则选项如下:

def func1():
    global inner_func
    inner_func = func2
    print 1

def func2():
    print 2

inner_func = func1

for i in range(5):
    inner_func()
  • 使用而不是CPython
  • 使用
  • 编写C++模块并与
  • 接口
  • 如果可能,使用simd方法实现您的算法
  • 如果可能,在GPU硬件上移动计算,例如

您所说的“优化”是什么意思这里?内联?通常,与函数体相比,函数调用开销被忽略了。所以不确定它是否值得。与从文件中加载行并解析行的时间相比,传递函数或循环所花费的时间是多少?列表理解会更糟糕,因为它必须构建结果列表。说真的吗?您希望代码速度更快,但却不太可靠你在使用Python?PyPy会像这样内联调用;我找不到文档,但@katriealex:yep上有一个愚蠢的例子,这是有道理的。这样的内联是一个相对简单的优化。JIT解释器做了很多更有趣的事情,免责声明应该放在顶部-这是这个答案中迄今为止最重要的声明。+1,但对于b公平地说,我仍然认为这很可怕,我使用Python是因为它的其他吸引人的特性,而不是因为它的动态特性。事实上,我很乐意放弃很多…@phihag:我不同意。今天(2011年8月)有人说“Python”99%的可能性他指的是正式实施。也许几年后情况会有所不同