为什么mesh python代码比分解的代码慢?

为什么mesh python代码比分解的代码慢?,python,performance,Python,Performance,我在研究线程时发现了令人惊讶的python行为 如果我从该线程运行简单的python代码 #!/usr/bin/env python from __future__ import print_function import time import sys count = 0 start_time = time.time() for line in sys.stdin: count += 1 delta_sec = time.time() - start_time if delta

我在研究线程时发现了令人惊讶的python行为

如果我从该线程运行简单的python代码

#!/usr/bin/env python
from __future__ import print_function
import time
import sys


count = 0
start_time = time.time()

for line in sys.stdin:
    count += 1

delta_sec = time.time() - start_time
if delta_sec >= 0:
    lines_per_sec = int(round(count/delta_sec))
    print("Read {0:n} lines in {1:.2f} seconds. LPS: {2:n}".format(count, delta_sec, lines_per_sec))
它以11.5MLPS的速度工作,当我将整个脚本分解为单个函数时

#!/usr/bin/env python
from __future__ import print_function
import time
import sys


def test(input):
    count = 0
    start_time = time.time()

    for line in input:
        count += 1

    delta_sec = time.time() - start_time
    if delta_sec >= 0:
        lines_per_sec = int(round(count/delta_sec))
        print("Read {0:n} lines in {1:.2f} seconds. LPS: {2:n}".format(count, delta_sec, lines_per_sec))


if __name__ == "__main__":
    test(sys.stdin)
代码速度高达23M LPS

为什么这种简单的重构使我的代码速度提高了2倍


我已经在Ubuntu13.10上用python2.7运行了测试。

观察字节码帮助我回答了这个问题。 第一个脚本工作部分的字节码为:

 10          58 SETUP_LOOP              27 (to 88)
             61 LOAD_NAME                3 (sys)
             64 LOAD_ATTR                6 (stdin)
             67 GET_ITER         
        >>   68 FOR_ITER                16 (to 87)
             71 STORE_NAME               7 (line)
 11          74 LOAD_NAME                4 (count)
             77 LOAD_CONST               4 (1)
             80 INPLACE_ADD      
             81 STORE_NAME               4 (count)
             84 JUMP_ABSOLUTE           68
        >>   87 POP_BLOCK
 12          18 SETUP_LOOP              24 (to 45)
             21 LOAD_FAST                0 (input)
             24 GET_ITER
        >>   25 FOR_ITER                16 (to 44)
             28 STORE_FAST               3 (line)
 13          31 LOAD_FAST                1 (count)
             34 LOAD_CONST               2 (1)
             37 INPLACE_ADD
             38 STORE_FAST               1 (count)
             41 JUMP_ABSOLUTE           25
        >>   44 POP_BLOCK
第二个脚本对应部分的字节码为:

 10          58 SETUP_LOOP              27 (to 88)
             61 LOAD_NAME                3 (sys)
             64 LOAD_ATTR                6 (stdin)
             67 GET_ITER         
        >>   68 FOR_ITER                16 (to 87)
             71 STORE_NAME               7 (line)
 11          74 LOAD_NAME                4 (count)
             77 LOAD_CONST               4 (1)
             80 INPLACE_ADD      
             81 STORE_NAME               4 (count)
             84 JUMP_ABSOLUTE           68
        >>   87 POP_BLOCK
 12          18 SETUP_LOOP              24 (to 45)
             21 LOAD_FAST                0 (input)
             24 GET_ITER
        >>   25 FOR_ITER                16 (to 44)
             28 STORE_FAST               3 (line)
 13          31 LOAD_FAST                1 (count)
             34 LOAD_CONST               2 (1)
             37 INPLACE_ADD
             38 STORE_FAST               1 (count)
             41 JUMP_ABSOLUTE           25
        >>   44 POP_BLOCK
我看到这两个代码之间的实际区别是使用LOAD_NAME vs LOAD_FAST和STORE_NAME vs STORE_FAST操作码。 文件上说, LOAD_FAST仅使用索引进行查找,而LOAD_NAME按字符串名称查找变量。
第一种方法的速度要快两倍。

请尝试
input=sys.stdin以获取输入中的行:…
在您的第一个脚本中,此方法不会首先加快速度script@Leonardo.Z:没关系。属性查找只发生一次。我在CPython 2.7、Windows Server 2008 R2上尝试了您的示例,但无法重现此行为。两种变体的LPS大致相同。我不知道你观察的原因,甚至无法做出“有根据的猜测”@Thorsten Kranz我可以建议,在你的设置中,从文件读取速度太慢,无法观察本地/全局查找之间的差异。将'sys.stdin'/'input'更改为xrange(10**8)后,您是否有相同的LPS?标准python'dis'模块几乎可以反汇编所有:)