简体   繁体   English

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

[英]python - performance difference between the two implementations

How are the following two implementations have different performance in Python? 以下两个实现在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)))

AND

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

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

The first implementation is faster than the second for inputs of the order of 10^6 lines. 对于10 ^ 6行量级的输入,第一种实现比第二种实现快。 Why so? 为什么这样?

>>> 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 is your first function. first是您的第一个功能。 second is your second function. second是您的第二个功能。

dis tells one of the reasons why the first one is faster. dis讲述了第一个更快的原因之一。

Two primary reasons: 两个主要原因:

  • The 2nd code explicitly constructs a list and sorts it afterwards, while the 1st version lets sorted create only a internal list while sorting at the same time. 第2个代码显式构造一个列表,然后对其进行排序,而第1个版本让sorted仅创建一个内部列表,同时进行排序。
  • The 2nd code explicitly loops over a list with for (on the Python VM), while the 1st version implicitly loops with imap (over the underlaying structure in C). 第二个代码显式地循环使用for (在Python VM上)的列表,而第一个代码隐式地循环使用imap (在C中的底层结构上)。

Anyways, why is StringIO in there? 无论如何,为什么StringIO在其中? The most straightforward and probably fastest way is: 最直接,可能最快的方法是:

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

Do a step-by-step conversion from the second to the first one and see how the performance changes with each step. 从第二个步骤到第一个步骤进行逐步转换,看看性能如何随着每个步骤而变化。

  1. Remove line.strip. 删除line.strip。 This will cause some speed up, whether it would be significant is another matter. 这将导致速度加快,这是否有意义是另一回事。 The stripping is superfluous as has been mentioned by you and THC4k. 如您和THC4k所述,剥离是多余的。
  2. Then replace the for loop using l.append with map(int, sys.stdin). 然后使用l.append替换map(int,sys.stdin)的for循环。 My guess is that this would give a significant speed-up. 我的猜测是,这将大大提高速度。
  3. Replace map and l.sort with imap and sorted . imapsorted替换mapl.sort My guess is that it won't affect the performance, there could be a slight slowdown, but it would be far from significant. 我的猜测是,它不会影响性能,可能会略有下降,但远不算很大。 Between the two, I'd usually go with the former, but with Python 3 on the horizon the latter is probably preferable. 在这两者之间,我通常会选择前者,但是随着Python 3的出现,后者可能更可取。
  4. Replace the for loop using print with print '\\n'.join(...) . 使用print将for循环替换为print '\\n'.join(...) My guess is that this would be another speed-up, but it would cost you some memory. 我的猜测是这将是另一种提速,但是会花费您一些内存。
  5. Add cStringIO (which is completely unnecessary by the way) to see how it affects performance. 添加cStringIO(顺便说一句完全没有必要)以查看它如何影响性能。 My guess is that it would be slightly slower, but not enough to counter 4 and 2. 我的猜测是它会稍微慢一些,但不足以抵消4和2。

Then, if you try THC4k's answer, it would probably be faster than all of the above, while being simpler and easier to read, and using less memory than 4 and 5. It has slightly different behaviour (it doesn't strip leading zeros from the numbers). 然后,如果您尝试THC4k的答案,它可能会比上述所有方法更快,同时更简单易读,并且使用的内存少于4和5。它的行为略有不同(它不会从中去除前导零。号码)。

Of course, try this yourself instead of trusting anyone guesses. 当然,请自己尝试,而不要相信任何人的猜测。 Also run cProfile on your code and see which parts are losing most time. 另外,在代码上运行cProfile ,查看哪些部分浪费最多的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM