首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >字节码优化

字节码优化
EN

Stack Overflow用户
提问于 2016-06-09 23:26:58
回答 2查看 4.4K关注 0票数 13

这里有两个简单的例子。在第一个示例中,append方法在循环中生成LOAD_ATTR指令,在第二个示例中,它只生成一次,结果保存在变量(即缓存)中。提醒:我记得,这个任务的extend方法比这个要快得多

代码语言:javascript
复制
setup = \
"""LIST = []
ANOTHER_LIST = [i for i in range(10**7)]

def appender(list, another_list):
    for elem in another_list:
        list.append(elem)

def appender_optimized(list, another_list):
    append_method = list.append
    for elem in another_list:
        append_method(elem)"""


import timeit

print(timeit.timeit("appender(LIST, ANOTHER_LIST)", setup=setup, number=10))
print(timeit.timeit("appender_optimized(LIST, ANOTHER_LIST)", setup=setup, number=10))

结果:

代码语言:javascript
复制
11.92684596051036
7.384205785584728

4.6秒的差(即使对于这么大的列表)也不是笑话--对于我来说,这种差异不能算作“微观优化”。为什么Python不为我做呢?因为字节码必须是源代码的精确反映?编译器甚至可以优化任何东西吗?例如,

代码语言:javascript
复制
def te():
    a = 2
    a += 1
    a += 1
    a += 1
    a += 1

产生

代码语言:javascript
复制
LOAD_FAST                0 (a)
LOAD_CONST               2 (1)
INPLACE_ADD
STORE_FAST               0 (a)

4次而不是优化成一个+= 4。还是它优化了一些著名的事情,比如产生位移位而不是乘以2?我是不是误解了一些基本的语言概念?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-09 23:41:47

Python是一种动态语言。这意味着您在如何编写代码方面有很大的自由。由于python暴露的大量内省(这是非常有用的BTW),许多优化都无法执行。例如,在您的第一个示例中,python无法知道调用它时list的数据类型是什么。我可以创建一个非常奇怪的课程:

代码语言:javascript
复制
class CrazyList(object):
    def append(self, value):
        def new_append(value):
            print "Hello world"

        self.append = new_append

显然,这是没有用的,但是我可以写这个,而且它是有效的python。如果要将此类型传递给上述函数,代码将与“缓存”append函数的版本不同。

我们可以为+=编写一个类似的示例(如果“编译器”对其进行优化,它可能会产生副作用,不会被执行)。

为了进行有效的优化,python必须知道您的类型..。对于绝大多数的代码来说,它没有获得类型数据的(傻瓜)的方法,所以它甚至不尝试大多数优化。

请注意,这是一个微优化(和一个有据可查优化)。它在某些情况下是有用的,但在大多数情况下,如果您编写惯用的python,它是不必要的。例如,您的list示例最好使用.extend方法编写,正如您在文章中所指出的那样。大多数情况下,如果您的循环足够紧,使得方法的查找时间在您的整个程序运行时非常重要,那么要么您应该找到一种方法来重写该循环以提高效率,或者甚至将计算推入一种更快的语言(例如C)。有些库非常擅长这个(numpy)。

尽管如此,在称为“窥视孔优化器”的阶段,“编译器”可以安全地完成一些优化。它会为你做一些简单的常量折叠:

代码语言:javascript
复制
>>> import dis
>>> def foo():
...     a = 5 * 6
... 
>>> dis.dis(foo)
  2           0 LOAD_CONST               3 (30)
              3 STORE_FAST               0 (a)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        

在某些情况下,它会缓存值以供以后使用,或者将一种类型的对象转换为另一种类型:

代码语言:javascript
复制
>>> def translate_tuple(a):
...   return a in [1, 3]
... 
>>> import dis
>>> dis.dis(translate_tuple)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               3 ((1, 3))
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE

(注意,列表被转换为tuple并缓存-在python3.2+中,set文本也可以转换为frozenset和缓存)。

票数 9
EN

Stack Overflow用户

发布于 2016-06-09 23:36:14

一般来说,Python几乎没有对任何东西进行优化。它甚至不会优化像x = x这样的琐碎事情。Python是如此动态,因此正确地这样做是非常困难的。例如,不能在第一个示例中自动缓存list.append方法,因为它可以在另一个线程中进行更改,这在更静态的语言(如Java )中是无法完成的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37737740

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档