我使用python来解决SPOJ的大输入测试problem并遇到了一个非常奇怪的事件。我提交了相同的 使用PyPy和Python 2的代码。结果如下所示:
与CPython相比,使用PyPy的代码跑得更快,正如预期的那样。但与此同时,内存使用量增加了7倍!我在网上进行了搜索,但我找不到任何证据表明PyPy的内存使用量远远超过CPython。可以解释一下内存使用量的巨大差异吗?
我也认为可能是因为我的代码。因此,我在下面发布了我的代码:
import io, sys, atexit, os
sys.stdout = io.BytesIO()
atexit.register(lambda: sys.__stdout__.write(sys.stdout.getvalue()))
sys.stdin = io.BytesIO(sys.stdin.read())
raw_input = lambda: sys.stdin.readline().rstrip()
line = list(map(int,raw_input().split()))
num, k = line
ans = 0
for i in xrange(0,num):
if int(raw_input())%k == 0:
ans += 1;
print(ans)
有人可以告诉我吗?
答案 0 :(得分:4)
首先,我无法重现结果。不知道SPOJ使用了哪些版本/设置。对于以下实验,使用PyPy 5.8.0和CPython 2.7.12。
作为测试用例,使用了大小约为110MB
的最大可能输入文件:
#create_data.py
print 10**6, 33
for i in xrange(10**6):
print 10**9
>> python create_data.py > input.in
现在运行/usr/bin/time -v XXX solution.py < input.py
会产生:
Interpreter MaximalResidentSize
PyPy: 278 Mb
CPython: 222 Mb
PyPy需要更多的内存。 CPython和PyPy使用不同的垃圾收集器策略,我认为PyPy的权衡更快,但要使用更多的内存。来自PyPy的人有一个great article关于他们的垃圾收集器及其与CPython的比较。
其次,我不相信SPJO网站上的数字。 system.stdin.read()
会将整个文件读入内存。 python文档甚至是says:
要读取文件的内容,请调用f.read(size),它读取一些数据并将其作为字符串返回。 size是可选的数字参数。当省略大小或为负时,将读取并返回文件的全部内容; 如果文件是机器内存的两倍则会出现问题。
根据假设,最坏的情况包括在他们的测试用例中,内存使用量应该至少是文件的大小(110 MB),因为你使用std.stdin.read()
甚至两倍的大小,因为你正在处理数据。
实际上,我不确定,整个问题是值得的 - 使用raw_input()
可能足够快 - 我会信任python做正确的事情。 CPython通常缓冲stdout
和stdin
(如果重定向到文件,则完全缓冲,或者为控制台进行行缓冲),并且必须使用命令行选项-u
到{{3} }。
但是如果你真的想确定,可以使用sys.stdin
的文件对象迭代器,因为CPython手册页指出:
-u强制stdin,stdout和stderr完全无缓冲。上 重要的系统,也把stdin,stdout和stderr放进去 二进制模式。请注意,在xread中有内部缓冲 lines(),readlines()和 file-object iterators(“for line in sys.stdin“),不受此选项的影响。工作 围绕这个,你会想在里面使用“sys.stdin.readline()” 一个“while 1:”循环。
这意味着您的程序可能如下所示:
import sys
num, k = map(int,raw_input().split())
ans = 0
for line in sys.stdin:
if int(line)%k == 0:
ans += 1
print(ans)
这具有很大的优势,即此变体仅使用大约7MB内存。
另一个经验教训是,如果您害怕,有人在无缓冲模式下运行程序,则不应使用sys.stdin.readline()
。
一些进一步的实验(我的cpu时钟下降)
CPython CPython -u PyPy PyPy -u
original 28sec/221MB 25sec/221MB 3sec/278MB 3sec/278MB
raw_input() 29sec/7MB 110sec/7MB 7sec/75MB 100sec/63MB
readline() 38sec/7MB 130sec/7MB 5sec/75MB 100sec/63MB
readlines() 20sec/560MB 20sec/560MB 4sec/1.4GB 4sec/1.4G
file-iterator 17sec/7MB 17sec/7MB 4sec/68MB 100sec/62MB
有一些要点:
raw_input()
和sys.stdin.read_line()
具有相同的效果raw_input()
是缓冲的,但是这个缓冲区似乎与文件对象迭代器的缓冲区略有不同,它至少对这个文件的性能优于raw_input()
。sys.stdin.readlines()
的内存开销似乎非常高,至少只要行很短。-u
:对于PyPy -u
也关闭文件对象迭代器的缓冲(可能是一个bug?)。 / LI>
醇>