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

izh*_*hak 17 python optimization compiler-optimization

说,我有一个代码,从循环中调用一些函数数百万次,我希望代码快:

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

def inner_function(line):
    # do something
    pass
Run Code Online (Sandbox Code Playgroud)

它不一定是文件处理,它可以是例如从函数绘制线调用的函数绘制点.这个想法是逻辑上这两者必须分开,但从性能的角度来看,它们应该尽可能快地一起行动.

Python会自动检测并优化这些内容吗?如果没有 - 有没有办法给它一个线索呢?可能使用一些额外的外部优化器?...

Eli*_*sky 15

Python没有内联函数调用,因为它具有动态特性.从理论上讲,inner_function可以做一些将名称重新绑定inner_function到其他东西的东西 - 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()
Run Code Online (Sandbox Code Playgroud)

打印:

1
2
2
2
2
Run Code Online (Sandbox Code Playgroud)

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

也就是说,您可以使用像byteplay或类似工具一起破解某些东西- 将内部函数反汇编为字节码并将其插入外部函数,然后重新组装.第二个想法,如果你的代码性能足够严重以保证这样的黑客攻击,那么只需用C语言重写它.Python有很多FFI选项.


这与官方CPython实现都有关.运行时JITting解释器(如PyPy或可悲的已解散的Unladen Swallow)理论上可以检测正常情况并执行内联.唉,我对PyPy不太熟悉,知道它是否会这样做,但它绝对可以.

  • PyPy会像这样内联调用; 我无法找到文档,但在http://morepypy.blogspot.com/2011/02/pypy-faster-than-c-on-carefully-crafted.html上有一个愚蠢的例子. (3认同)
  • @phihag:我不同意.今天(2011年8月)当一个人说"Python"时,他有99%的可能性意味着正式实施.也许几年后情况会有所不同 (3认同)

小智 13

哪个 Python?PyPy的将JIT编译器-几百或几十后(取决于有多少操作码在每次迭代执行)迭代左右-开始跟踪执行,忘了Python函数沿途呼叫,并编译所收集的信息成片的优化的机器代码,可能没有任何使函数调用本身发生的逻辑残余.跟踪是线性的,JIT的后端甚至不知道有一个函数调用,它只是看到两个函数的指令在执行时混合在一起.(这是一个完美的情况下,如存在于循环分支或全部重复采取相同的分支,有些代码是不适合这种JIT编译和痕迹很快失效,它们产生很大的加速之前,虽然这是相当罕见.)

现在,CPython,许多人在谈到"Python"或Python解释器时的意思并不那么聪明.它是一个简单的字节码VM,将尽职尽责地执行与每次迭代中反复调用函数相关的逻辑.但话又说回来,如果表现如此重要,你为什么还要使用翻译呢?考虑在本机代码中编写热循环(例如,作为C扩展或在Cython中),如果保持这种开销尽可能低的那么重要.

除非你每次迭代只进行一点点的数字处理,否则你不会得到任何大的改进.


Chr*_*gan 5

如果用"Python"表示CPython,通常使用的实现,没有.

如果用"Python"你碰巧意味着Python语言的任何实现,是的.PyPy可以优化很多,我相信它的方法JIT应该处理这样的情况.