Eug*_*lev 10 python performance
在调查线程时我发现了令人惊讶的python行为为什么在C++中读取stdin的行比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))
Run Code Online (Sandbox Code Playgroud)
它的工作速度为11.5M LPS,当我将整个脚本分解为单个功能时
#!/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)
Run Code Online (Sandbox Code Playgroud)
代码速度高达23M LPS.
为什么这种简单的重构使我的代码加快了2倍?
我在Ubuntu 13.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
Run Code Online (Sandbox Code Playgroud)
第二个脚本对应部分的字节码为:
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
Run Code Online (Sandbox Code Playgroud)
我看到这两个代码之间的实际差异是LOAD_NAME与LOAD_FAST以及STORE_NAME与STORE_FAST操作码的使用。文档http://docs.python.org/2.7/library/dis.html#opcode-LOAD_FAST表示LOAD_FAST仅使用索引进行查找,而LOAD_NAME查找按字符串名称进行变量。第一种方法要快两倍。
| 归档时间: |
|
| 查看次数: |
266 次 |
| 最近记录: |