Python解释代码优化

发布于 2024-11-29 11:08:54 字数 310 浏览 0 评论 0原文

考虑下面的代码片段:

dict [name] = 0
dict [name] += 1
dict [name] += 1

Does the python解释器自动识别对字典值的重复引用并使用缓存的本地引用代替?,有点类似于C/C++的别名优化,变成这样:

value = dict [name]
value = 0
value += 1
value += 1

显然,这不是一个大的问题需要手动执行此操作,但我很好奇是否确实有必要。如有任何见解、反馈等,我们将不胜感激。

Consider the following code snippet:

dict [name] = 0
dict [name] += 1
dict [name] += 1

Does the python interpreter automatically recognise the repeated references to the dictionary value and use a cached local reference instead?, somewhat akin to the aliasing optimisations of C/C++, becoming something like so:

value = dict [name]
value = 0
value += 1
value += 1

Obviously, it's not a big deal to do this manually but I'm curious if it's actually necessary. any insight, feedback, etc is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

指尖凝香 2024-12-06 11:08:54

您可以通过反汇编程序运行它来找出:

import dis

def test():
    name = 'test'
    tdict = {}
    tdict[name] = 0
    tdict[name] += 1
    tdict[name] += 1

dis.dis(test)

运行我们得到:

 13           0 LOAD_CONST               1 ('test')
              3 STORE_FAST               0 (name)

 14           6 BUILD_MAP                0
              9 STORE_FAST               1 (tdict)

 15          12 LOAD_CONST               2 (0)
             15 LOAD_FAST                1 (tdict)
             18 LOAD_FAST                0 (name)
             21 STORE_SUBSCR        

 16          22 LOAD_FAST                1 (tdict)
             25 LOAD_FAST                0 (name)
             28 DUP_TOPX                 2
             31 BINARY_SUBSCR       
             32 LOAD_CONST               3 (1)
             35 INPLACE_ADD         
             36 ROT_THREE           
             37 STORE_SUBSCR        

 17          38 LOAD_FAST                1 (tdict)
             41 LOAD_FAST                0 (name)
             44 DUP_TOPX                 2
             47 BINARY_SUBSCR       
             48 LOAD_CONST               3 (1)
             51 INPLACE_ADD         
             52 ROT_THREE           
             53 STORE_SUBSCR        
             54 LOAD_CONST               0 (None)
             57 RETURN_VALUE        

在本例中,LOAD_FAST 看起来正在加载 tdict的值>name 每次我们尝试访问它来执行增量时,所以答案似乎是否定的。

You can run it through the disassembler to find out:

import dis

def test():
    name = 'test'
    tdict = {}
    tdict[name] = 0
    tdict[name] += 1
    tdict[name] += 1

dis.dis(test)

Running this we get:

 13           0 LOAD_CONST               1 ('test')
              3 STORE_FAST               0 (name)

 14           6 BUILD_MAP                0
              9 STORE_FAST               1 (tdict)

 15          12 LOAD_CONST               2 (0)
             15 LOAD_FAST                1 (tdict)
             18 LOAD_FAST                0 (name)
             21 STORE_SUBSCR        

 16          22 LOAD_FAST                1 (tdict)
             25 LOAD_FAST                0 (name)
             28 DUP_TOPX                 2
             31 BINARY_SUBSCR       
             32 LOAD_CONST               3 (1)
             35 INPLACE_ADD         
             36 ROT_THREE           
             37 STORE_SUBSCR        

 17          38 LOAD_FAST                1 (tdict)
             41 LOAD_FAST                0 (name)
             44 DUP_TOPX                 2
             47 BINARY_SUBSCR       
             48 LOAD_CONST               3 (1)
             51 INPLACE_ADD         
             52 ROT_THREE           
             53 STORE_SUBSCR        
             54 LOAD_CONST               0 (None)
             57 RETURN_VALUE        

It looks like, in this case, that LOAD_FAST is loading up the values of tdict and name each time we try to access it to perform the increment, so the answer would appear to be no.

穿越时光隧道 2024-12-06 11:08:54

仅仅通过检查代码是不可能实现这种类型的优化的。您的名称 dict 可能不是指本机字典,而是指实现 __setitem__ 的用户定义对象,并且必须调用该方法三次。在运行时,复杂的实现可以记录名称的实际值,并进行优化,但在运行之前无法在不破坏某些 Python 语义的情况下完成。

That type of optimization isn't possible simply by inspecting the code. Your name dict could refer not to a native dictionary, but a user-defined object that implements __setitem__, and that method has to be called three times. At runtime, a sophisticated implementation could note the actual value of the name, and make an optimization, but it can't be done before runtime without breaking some Python semantics.

北音执念 2024-12-06 11:08:54

不,因为那行不通,你甚至用你自己的代码证明了这一点——它实际上并不等同:

>>> a = {}
>>> name = 'x'
>>> a[name] = 0
>>> a[name] += 1
>>> a[name] += 1
>>> a[name] # ok no suprises so far
2
>>> a = {}
>>> a[name] = 0
>>> x = a[name] # x is now literally `0`, not some sort of reference to a[name]
>>> x
0
>>> x += 1
>>> x += 1
>>> a[name] # so this never changed
0
>>>

Python 没有 C 风格的“引用”。您想到的仅适用于可变类型,例如 list。这是 Python 的一个非常基本的属性,在进行 Python 编程时,您可能应该忘记 C 教给您的有关变量的所有内容。

No, because that would not work, and you even demonstated that with your own code - it's actually not equivalent:

>>> a = {}
>>> name = 'x'
>>> a[name] = 0
>>> a[name] += 1
>>> a[name] += 1
>>> a[name] # ok no suprises so far
2
>>> a = {}
>>> a[name] = 0
>>> x = a[name] # x is now literally `0`, not some sort of reference to a[name]
>>> x
0
>>> x += 1
>>> x += 1
>>> a[name] # so this never changed
0
>>>

Python does not have C-ish "references". What you had in mind would work only for mutable types such as list. This is a very fundamental property of Python and you should probably forget everything C taught you about variables when programming Python.

酒解孤独 2024-12-06 11:08:54

将您的两个示例更改为如下所示:

#v1.py
di = {}
name = "hallo"
di[name] = 0
for i in range(2000000):
    di[name] += 1

并且

#v2.py
di = {}
name = "hallo"
di[name] = 0
value = di[name]
for i in range(2000000):
    value += 1

您可以在以下测试中看到,v2 更快,但 pypy 更快:-)

$ time python2.7 v1.py
real    0m0.788s
user    0m0.700s
sys     0m0.080s

$ time python2.7 v2.py
real    0m0.586s
user    0m0.490s
sys     0m0.090s

$ time pypy v1.py
real    0m0.203s
user    0m0.210s
sys     0m0.000s

$ time pypy v2.py
real    0m0.117s
user    0m0.080s
sys     0m0.030s

SO:为单个解释器优化代码并不好(我还没有测试 Jython例如...),但是当 有人 优化解释器时就很棒了...

Changing your two examples into something like this:

#v1.py
di = {}
name = "hallo"
di[name] = 0
for i in range(2000000):
    di[name] += 1

and

#v2.py
di = {}
name = "hallo"
di[name] = 0
value = di[name]
for i in range(2000000):
    value += 1

You can see in the following tests, that v2 is faster, but pypy is much faster :-)

$ time python2.7 v1.py
real    0m0.788s
user    0m0.700s
sys     0m0.080s

$ time python2.7 v2.py
real    0m0.586s
user    0m0.490s
sys     0m0.090s

$ time pypy v1.py
real    0m0.203s
user    0m0.210s
sys     0m0.000s

$ time pypy v2.py
real    0m0.117s
user    0m0.080s
sys     0m0.030s

SO: it's not good to optimize code for a single interpreter (I have not tested Jython for example...), but it's great when someone optimizes the interpreter...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文