gpt4 book ai didi

python - 与 CPython 相比,PyPy 占用大量内存

转载 作者:太空狗 更新时间:2023-10-30 02:54:38 32 4
gpt4 key购买 nike

我用python解决了SPOJ的大输入测试problem并遇到了一件非常奇怪的事情。我提交了相同 使用 PyPy 和 Python 2 编写代码。结果如下所示:

spoj large input test

如预期的那样,与 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)

有人可以告诉我吗?

最佳答案

首先,我无法重现结果。不知道 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 :

To read a file’s contents, call f.read(size), which reads some quantity of data and returns it as a string. size is an optional numeric argument. When size is omitted or negative, the entire contents of the file will be read and returned; it’s your problem if the file is twice as large as your machine’s memory.

假设最坏的情况已包含在他们的测试用例中,内存使用量应至少为文件大小 (110 MB),因为您使用 std.stdin.read()甚至两倍大小,因为您正在处理数据。


实际上,我不确定,所有的麻烦都是值得的 - 使用 raw_input()可能足够快——我只相信 python 会做正确的事。 CPython 通常缓冲 stdoutstdin (如果它们被重定向到文件,则完全缓冲,或者为控制台行缓冲)并且您必须使用命令行选项 -uswitch it off .

但如果你真的想确定,你可以使用 sys.stdin 的文件对象迭代器,因为正如 CPython 手册页所述:

-u Force stdin, stdout and stderr to be totally unbuffered. On systems where it matters, also put stdin, stdout and stderr in binary mode. Note that there is internal buffering in xread‐ lines(), readlines() and file-object iterators ("for line in sys.stdin") which is not influenced by this option. To work around this, you will want to use "sys.stdin.readline()" inside a "while 1:" loop.

这意味着您的程序可能如下所示:

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

有一些要点:

  1. raw_input()sys.stdin.read_line()具有相同的性能
  2. raw_input()被缓冲,但这个缓冲区似乎与文件对象迭代器的缓冲区有点不同,它优于 raw_input()至少对于这个文件。
  3. sys.stdin.readlines() 的内存开销看起来很高,至少只要线条很短。
  4. 文件对象迭代器在 CPython 和 PyPy 中有不同的行为,如果选项 -u用于:PyPy -u还关闭文件对象迭代器的缓冲(可能是错误?)。

关于python - 与 CPython 相比,PyPy 占用大量内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45117672/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com