python - 两个实现之间的性能差异

时间:2011-01-10 17:42:59

标签: python performance sorting

以下两种实现如何在Python中具有不同的性能?

from cStringIO import StringIO
from itertools import imap
from sys import stdin
input = imap(int, StringIO(stdin.read()))
print '\n'.join(imap(str, sorted(input)))

import sys
for line in sys.stdin:
    l.append(int(line.strip('\n')))

l.sort()
for x in l:
    print x

对于10 ^ 6行的输入,第一个实现比第二个更快。为什么这样?

3 个答案:

答案 0 :(得分:3)

>>> dis.dis(first)
  2           0 LOAD_GLOBAL              0 (imap)
              3 LOAD_GLOBAL              1 (int)
              6 LOAD_GLOBAL              2 (StringIO)
              9 LOAD_GLOBAL              3 (stdin)
             12 LOAD_ATTR                4 (read)
             15 CALL_FUNCTION            0
             18 CALL_FUNCTION            1
             21 CALL_FUNCTION            2
             24 STORE_FAST               0 (input)
             27 LOAD_CONST               0 (None)
             30 RETURN_VALUE        
>>> dis.dis(second)
  2           0 SETUP_LOOP              48 (to 51)
              3 LOAD_GLOBAL              0 (sys)
              6 LOAD_ATTR                1 (stdin)
              9 CALL_FUNCTION            0
             12 GET_ITER            
        >>   13 FOR_ITER                34 (to 50)
             16 STORE_FAST               0 (line)

  3          19 LOAD_GLOBAL              2 (l)
             22 LOAD_ATTR                3 (append)
             25 LOAD_GLOBAL              4 (int)
             28 LOAD_FAST                0 (line)
             31 LOAD_ATTR                5 (strip)
             34 LOAD_CONST               1 ('\n')
             37 CALL_FUNCTION            1
             40 CALL_FUNCTION            1
             43 CALL_FUNCTION            1
             46 POP_TOP             
             47 JUMP_ABSOLUTE           13
        >>   50 POP_BLOCK           

  4     >>   51 LOAD_GLOBAL              2 (l)
             54 LOAD_ATTR                6 (sort)
             57 CALL_FUNCTION            0
             60 POP_TOP             
             61 LOAD_CONST               0 (None)
             64 RETURN_VALUE        

first是你的第一个功能。 second是你的第二个功能。

dis讲述了第一个更快的原因之一。

答案 1 :(得分:2)

两个主要原因:

  • 第二个代码显式构造一个列表并在之后对其进行排序,而第一个版本允许sorted在同时排序的同时创建一个内部列表。
  • 第二个代码显式地循环使用for的列表(在Python VM上),而第一个版本隐式循环使用imap(在C中的底层结构上)。

无论如何,为什么StringIO在那里?最直接也可能最快的方法是:

from sys import stdin, stdout
stdout.writelines(sorted(stdin, key=int))

答案 2 :(得分:1)

从第二步到第一步的逐步转换,看看性能如何随每一步而变化。

  1. 删除line.strip。这将导致一些加速,无论它是否重要是另一回事。正如你和THC4k所提到的那样,剥离是多余的。
  2. 然后使用map {int,sys.stdin}将l.append替换为for循环。我的猜测是,这会显着提高速度。
  3. mapl.sort替换为imapsorted。我的猜测是,它不会影响性能,可能会有轻微的减速,但它远非显着。在两者之间,我通常会选择前者,但在Python 3中,后者可能更适合。
  4. 使用printprint '\n'.join(...)替换for循环。我的猜测是,这将是另一次加速,但它会花费你一些记忆。
  5. 添加cStringIO(顺便说一下这完全没必要),看看它如何影响性能。我的猜测是它稍慢,但还不足以对抗4和2。
  6. 然后,如果你尝试THC4k的答案,它可能会比上述所有更快,同时更简单,更容易阅读,并且使用的内存少于4和5.它的行为略有不同(它不会剥离数字中的前导零。)

    当然,请亲自尝试,而不是相信任何猜测。同时在代码上运行cProfile,看看哪些部分正在丢失大部分时间。