如何通过简单的循环获得真正快速的Python

时间:2010-04-16 04:10:13

标签: python performance optimization

我正在解决SPOJ问题,INTEST。目标是指定测试用例的数量(n)和除数(k),然后为程序提供n个数字。该程序将接受stdin换行符上的每个数字,并在收到第n个数字后,将告诉您有多少可被k整除。

此问题的唯一挑战是让您的代码更快,因为k可以是最多10 ^ 7而n可以高达10 ^ 9。

我正在尝试用Python编写它并且无法加速它。有什么想法吗?


编辑2:我终于在10.54秒时通过了它。我几乎把你所有的答案用到了那里,因此很难选择一个“正确”,但我相信我选择的那个总结得最好。谢谢大家。最终传递代码如下。

编辑:我在附带的代码中包含了一些建议的更新。


不允许使用扩展程序和第三方模块。代码也由SPOJ评判机器运行,因此我无法更改解释器。

import sys
import psyco
psyco.full()

def main():
    from sys import stdin, stdout
    first_in = stdin.readline()
    thing = first_in.split()
    n = int(thing[0])
    k = int(thing[1])
    total = 0

    list = stdin.readlines()
    for item in list:
        if int(item) % k == 0:
            total += 1

    stdout.write(str(total) + "\n")

if __name__ == "__main__":
    main()

6 个答案:

答案 0 :(得分:14)

[编辑反映新发现并在代码上传递代码]

通常,在使用Python进行欺骗时:

  • 不要使用“raw_input”,请使用sys.stdin.readlines()。这可以为大输入带来改变。另外,如果可能的话(对于这个问题),一次读取所有内容(sys.stdin .readlines()),而不是逐行读取(“for sys.stdin中的行...”)。
  • 同样,不要使用“print”,使用sys.stdout.write() - 并且不要忘记“\ n”。当然,这仅在多次打印时才有意义。
  • 正如S.Mark建议的那样,使用psyco。它可用于python2.5和python2.6,在spoj(测试它,它就在那里,并且很容易发现:使用psyco的解决方案通常具有~35Mb的内存使用偏移量)。这很简单:只需在“import sys”之后添加:import psyco; psyco.full()
  • 正如贾斯汀建议的那样,将你的代码(除了psyco咒语)放在一个函数中,然后在你的代码末尾调用它
  • 有时创建列表并检查其长度可能比创建列表和添加其组件更快。
  • 赞成“for”和“while”的列表推导(以及生成器表达式,如果可能)。对于某些构造,map / reduce / filter也可以加速您的代码。

使用(部分)这些指导原则,我设法通过了INTEST。但仍在测试替代品。

答案 1 :(得分:8)

嘿,我知道它在时限内。我使用了以下内容:

  • Psyco with Python 2.5。
  • 一个带有变量的简单循环,以便在
  • 中保持计数
  • 我的代码全部在main()函数中(除了psyco导入),我调用了它。

最后一个是有所作为的。我认为它与变量可见性有关,但我不完全确定。我的时间是10.81秒。你可以通过列表理解来加快速度。

编辑:

使用列表理解将我的时间缩短到8.23秒。将函数内部的from sys import stdin, stdout行稍微削减,以便将时间缩短到8.12秒。

答案 2 :(得分:6)

使用psyco,它会JIT你的代码,当有大循环和计算时非常有效。

修改:看起来不允许使用第三方模块,

所以,你可以尝试将你的循环转换为列表推导,它应该在C级运行,所以它应该更快一点。

sum(1 if int(line) % k == 0 else 0 for line in sys.stdin)

答案 3 :(得分:3)

就在最近Alex Martinelli说在函数内调用代码,胜过模块中运行的代码(我找不到帖子)

那么,你为什么不试试呢?

import sys
import psyco

psyco.full1()

def main():

    first_in = raw_input()
    thing = first_in.split()
    n = int(thing[0])
    k = int(thing[1])
    total = 0
    i = 0

    total = sum(1 if int(line) % k == 0 else 0 for line in sys.stdin)

    print total
if __name__ == "__main__":
    main()
IIRC原因是函数内部的代码可以被优化。

答案 4 :(得分:3)

使用精神上的列表理解会适得其反。

此代码:

 count = 0
 for l in sys.stdin:
     count += not int(l)%k

的运行速度是

的两倍
count = sum(not int(l)%k for l in sys.stdin)

使用心理学时。

答案 5 :(得分:2)

对于其他读者,here is the INTEST problem statement。它旨在进行I / O吞吐量测试。

在我的系统上,通过使用以下代码替换循环,我可以节省15%的执行时间:

print sum(1 for line in sys.stdin if int(line) % k == 0)